//***************************************************************************** // // SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: MIT // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // // File: nvt_edidext_861.c // // Purpose: the provide edid 861 extension related services // //***************************************************************************** #include "nvBinSegment.h" #include "nvmisc.h" #include "edid.h" PUSH_SEGMENTS #define EIA_TIMING(hv,hfp,hsw,ht,hsp,vv,vfp,vsw,vt,vsp,rrx1k,ip,aspect,rep,format) \ {hv,0,hfp,hsw,ht,(hsp)=='-',vv,0,vfp,vsw,vt,(vsp)=='-',(ip)=='i' ? NVT_INTERLACED:NVT_PROGRESSIVE,\ 0,{0,((rrx1k)+500)/1000,rrx1k,((1?aspect)<<16)|(0?aspect),rep,{0},{0},{0},{0},NVT_STATUS_EDID_861STn(format),"CEA-861B:#"#format""}} #define NVT_TIMING(hv,hfp,hsw,ht,hsp,vv,vfp,vsw,vt,vsp,rrx1k,ip,aspect,rep,format,name) \ {hv,0,hfp,hsw,ht,(hsp)=='-',vv,0,vfp,vsw,vt,(vsp)=='-',(ip)=='i' ? NVT_INTERLACED:NVT_PROGRESSIVE,\ 0,{0,((rrx1k)+500)/1000,rrx1k,((1?aspect)<<16)|(0?aspect),rep,{0},{0},{0},{0},NVT_TYPE_NV_PREDEFINEDn(format),name}} #define HDMI_EXT_TIMING(hv,hfp,hsw,ht,hsp,vv,vfp,vsw,vt,vsp,rrx1k,ip,aspect,rep,format,name) \ {hv,0,hfp,hsw,ht,(hsp)=='-',vv,0,vfp,vsw,vt,(vsp)=='-',(ip)=='i' ? NVT_INTERLACED:NVT_PROGRESSIVE,\ 0,{0,((rrx1k)+500)/1000,rrx1k,((1?aspect)<<16)|(0?aspect),rep,{0},{0},{0},{0},NVT_STATUS_HDMI_EXTn(format),name}} DATA_SEGMENT(PAGE_DATA) CONS_SEGMENT(PAGE_CONS) static const NVT_TIMING EIA861B[]= { // all 64 EIA/CEA-861E timings EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 1),//640 x 480p @59.94/60 (Format 1) EIA_TIMING( 720, 16, 62, 858,'-', 480, 9,6, 525,'-', 59940,'p', 4:3, 0x1, 2),//720 x 480p @59.94/60 (Format 2) EIA_TIMING( 720, 16, 62, 858,'-', 480, 9,6, 525,'-', 59940,'p',16:9, 0x1, 3),//720 x 480p @59.94/60 (Format 3) EIA_TIMING(1280, 110, 40,1650,'+', 720, 5,5, 750,'+', 59940,'p',16:9, 0x1, 4),//1280 x 720p @59.94/60 (Format 4) EIA_TIMING(1920, 88, 44,2200,'+', 540, 2,5, 562,'+', 59940,'i',16:9, 0x1, 5),//1920 x 1080i @59.94/60 (Format 5) EIA_TIMING(1440, 38,124,1716,'-', 240, 4,3, 262,'-', 59940,'i', 4:3, 0x2, 6),//720(1440) x 480i @59.94/60 (Format 6) EIA_TIMING(1440, 38,124,1716,'-', 240, 4,3, 262,'-', 59940,'i',16:9, 0x2, 7),//720(1440) x 480i @59.94/60 (Format 7) EIA_TIMING(1440, 38,124,1716,'-', 240, 4,3, 263,'-', 59940,'p', 4:3, 0x2, 8),//720(1440) x 240p @59.94/60 (Format 8) EIA_TIMING(1440, 38,124,1716,'-', 240, 4,3, 263,'-', 59940,'p',16:9, 0x2, 9),//720(1440) x 240p @59.94/60 (Format 9) EIA_TIMING(2880, 76,248,3432,'-', 240, 4,3, 262,'-', 59940,'i', 4:3, 0x3ff,10),//(2880) x 480i @59.94/60 (Format 10) EIA_TIMING(2880, 76,248,3432,'-', 240, 4,3, 262,'-', 59940,'i',16:9, 0x3ff,11),//(2880) x 480i @59.94/60 (Format 11) EIA_TIMING(2880, 76,248,3432,'-', 240, 5,3, 263,'-', 59940,'p', 4:3, 0x3ff,12),//(2880) x 480p @59.94/60 (Format 12) EIA_TIMING(2880, 76,248,3432,'-', 240, 5,3, 263,'-', 59940,'p',16:9, 0x3ff,13),//(2880) x 480p @59.94/60 (Format 13) EIA_TIMING(1440, 32,124,1716,'-', 480, 9,6, 525,'-', 59940,'p', 4:3, 0x3,14),//1440 x 480p @59.94/60 (Format 14) EIA_TIMING(1440, 32,124,1716,'-', 480, 9,6, 525,'-', 59940,'p',16:9, 0x3,15),//1440 x 480p @59.94/60 (Format 15) EIA_TIMING(1920, 88, 44,2200,'+',1080, 4,5,1125,'+', 59940,'p',16:9, 0x1,16),//1920 x 1080p @59.94/60 (Format 16) EIA_TIMING( 720, 12, 64, 864,'-', 576, 5,5, 625,'-', 50000,'p', 4:3, 0x1,17),//720 x 576p @50 (Format 17) EIA_TIMING( 720, 12, 64, 864,'-', 576, 5,5, 625,'-', 50000,'p',16:9, 0x1,18),//720 x 576p @50 (Format 18) EIA_TIMING(1280, 440, 40,1980,'+', 720, 5,5, 750,'+', 50000,'p',16:9, 0x1,19),//1280 x 720p @50 (Format 19) EIA_TIMING(1920, 528, 44,2640,'+', 540, 2,5, 562,'+', 50000,'i',16:9, 0x1,20),//1920 x 1080i @50 (Format 20) EIA_TIMING(1440, 24,126,1728,'-', 288, 2,3, 312,'-', 50000,'i', 4:3, 0x2,21),//720(1440) x 576i @50 (Format 21) EIA_TIMING(1440, 24,126,1728,'-', 288, 2,3, 312,'-', 50000,'i',16:9, 0x2,22),//720(1440) x 576i @50 (Format 22) EIA_TIMING(1440, 24,126,1728,'-', 288, 2,3, 312,'-', 50000,'p', 4:3, 0x2,23),//720(1440) x 288p @50 (Format 23) EIA_TIMING(1440, 24,126,1728,'-', 288, 2,3, 312,'-', 50000,'p',16:9, 0x2,24),//720(1440) x 288p @50 (Format 24) EIA_TIMING(2880, 48,252,3456,'-', 288, 2,3, 312,'-', 50000,'i', 4:3, 0x3ff,25),//(2880) x 576i @50 (Format 25) EIA_TIMING(2880, 48,252,3456,'-', 288, 2,3, 312,'-', 50000,'i',16:9, 0x3ff,26),//(2880) x 576i @50 (Format 26) EIA_TIMING(2880, 48,252,3456,'-', 288, 2,3, 312,'-', 50000,'p', 4:3, 0x3ff,27),//(2880) x 288p @50 (Format 27) EIA_TIMING(2880, 48,252,3456,'-', 288, 2,3, 312,'-', 50000,'p',16:9, 0x3ff,28),//(2880) x 288p @50 (Format 28) EIA_TIMING(1440, 24,128,1728,'-', 576, 5,5, 625,'_', 50000,'p', 4:3, 0x3,29),//1440 x 576p @50 (Format 29) EIA_TIMING(1440, 24,128,1728,'-', 576, 5,5, 625,'_', 50000,'p',16:9, 0x3,30),//1440 x 576p @50 (Format 30) EIA_TIMING(1920, 528, 44,2640,'+',1080, 4,5,1125,'+', 50000,'p',16:9, 0x1,31),//1920 x 1080p @50 (Format 31) EIA_TIMING(1920, 638, 44,2750,'+',1080, 4,5,1125,'+', 23976,'p',16:9, 0x1,32),//1920 x 1080p @23.97/24 (Format 32) EIA_TIMING(1920, 528, 44,2640,'+',1080, 4,5,1125,'+', 25000,'p',16:9, 0x1,33),//1920 x 1080p @25 (Format 33) EIA_TIMING(1920, 88, 44,2200,'+',1080, 4,5,1125,'+', 29970,'p',16:9, 0x1,34),//1920 x 1080p @29.97/30 (Format 34) EIA_TIMING(2880, 64,248,3432,'-', 480, 9,6, 525,'-', 59940,'p', 4:3, 0x7,35),//(2880) x 480p @59.94/60 (Format 35) EIA_TIMING(2880, 64,248,3432,'-', 480, 9,6, 525,'-', 59940,'p',16:9, 0x7,36),//(2880) x 480p @59.94/60 (Format 36) EIA_TIMING(2880, 48,256,3456,'-', 576, 5,5, 625,'-', 50000,'p', 4:3, 0x7,37),//(2880) x 576p @50 (Format 37) EIA_TIMING(2880, 48,256,3456,'-', 576, 5,5, 625,'-', 50000,'p',16:9, 0x7,38),//(2880) x 576p @50 (Format 38) EIA_TIMING(1920, 32,168,2304,'+', 540,23,5, 625,'-', 50000,'i',16:9, 0x1,39),//1920 x 1080i @50 (Format 39) EIA_TIMING(1920, 528, 44,2640,'+', 540, 2,5, 562,'+',100000,'i',16:9, 0x1,40),//1920 x 1080i @100 (Format 40) EIA_TIMING(1280, 440, 40,1980,'+', 720, 5,5, 750,'+',100000,'p',16:9, 0x1,41),//1280 x 720p @100 (Format 41) EIA_TIMING( 720, 12, 64, 864,'-', 576, 5,5, 625,'-',100000,'p', 4:3, 0x1,42),//720 x 576p @100 (Format 42) EIA_TIMING( 720, 12, 64, 864,'-', 576, 5,5, 625,'-',100000,'p',16:9, 0x1,43),//720 x 576p @100 (Format 43) EIA_TIMING(1440, 24,126,1728,'-', 288, 2,3, 312,'-',100000,'i', 4:3, 0x2,44),//720(1440) x 576i @100 (Format 44) EIA_TIMING(1440, 24,126,1728,'-', 288, 2,3, 312,'-',100000,'i',16:9, 0x2,45),//720(1440) x 576i @100 (Format 45) EIA_TIMING(1920, 88, 44,2200,'+', 540, 2,5, 562,'+',119880,'i',16:9, 0x1,46),//1920 x 1080i @119.88/120 (Format 46) EIA_TIMING(1280, 110, 40,1650,'+', 720, 5,5, 750,'+',119880,'p',16:9, 0x1,47),//1280 x 720p @119.88/120 (Format 47) EIA_TIMING( 720, 16, 62, 858,'-', 480, 9,6, 525,'-',119880,'p', 4:3, 0x1,48),//720 x 480p @119.88/120 (Format 48) EIA_TIMING( 720, 16, 62, 858,'-', 480, 9,6, 525,'-',119880,'p',16:9, 0x1,49),//720 x 480p @119.88/120 (Format 49) EIA_TIMING(1440, 38,124,1716,'-', 240, 4,3, 262,'-',119880,'i', 4:3, 0x2,50),//720(1440) x 480i @119.88/120 (Format 50) EIA_TIMING(1440, 38,124,1716,'-', 240, 4,3, 262,'-',119880,'i',16:9, 0x2,51),//720(1440) x 480i @119.88/120 (Format 51) EIA_TIMING( 720, 12, 64, 864,'-', 576, 5,5, 625,'-',200000,'p', 4:3, 0x1,52),//720 x 576p @200 (Format 52) EIA_TIMING( 720, 12, 64, 864,'-', 576, 5,5, 625,'-',200000,'p',16:9, 0x1,53),//720 x 576p @200 (Format 53) EIA_TIMING(1440, 24,126,1728,'-', 288, 2,3, 312,'-',200000,'i', 4:3, 0x2,54),//720(1440) x 576i @200 (Format 54) EIA_TIMING(1440, 24,126,1728,'-', 288, 2,3, 312,'-',200000,'i',16:9, 0x2,55),//720(1440) x 576i @200 (Format 55) EIA_TIMING( 720, 16, 62, 858,'-', 480, 9,6, 525,'-',239760,'p', 4:3, 0x1,56),//720 x 480p @239.76/240 (Format 56) EIA_TIMING( 720, 16, 62, 858,'-', 480, 9,6, 525,'-',239760,'p',16:9, 0x1,57),//720 x 480p @239.76/240 (Format 57) EIA_TIMING(1440, 38,124,1716,'-', 240, 4,3, 262,'-',239760,'i', 4:3, 0x2,58),//720(1440) x 480i @239.76/240 (Format 58) EIA_TIMING(1440, 38,124,1716,'-', 240, 4,3, 262,'-',239760,'i',16:9, 0x2,59),//720(1440) x 480i @239.76/240 (Format 59) EIA_TIMING(1280,1760, 40,3300,'+', 720, 5,5, 750,'+',23976, 'p',16:9, 0x1,60),//1280 x 720p @23.97/24 (Format 60) EIA_TIMING(1280,2420, 40,3960,'+', 720, 5,5, 750,'+',25000, 'p',16:9, 0x1,61),//1280 x 720p @25 (Format 61) EIA_TIMING(1280,1760, 40,3300,'-', 720, 5,5, 750,'+',29970, 'p',16:9, 0x1,62),//1280 x 720p @29.97/30 (Format 62) EIA_TIMING(1920, 88, 44,2200,'+',1080, 4,5,1125,'+',119880,'p',16:9, 0x1,63),//1920 x 1080p @119.88/120 (Format 63) EIA_TIMING(1920, 528, 44,2640,'+',1080, 4,5,1125,'+',100000,'p',16:9, 0x1,64),//1920 x 1080p @100 (Format 64) // Following modes are from CEA-861F EIA_TIMING(1280,1760, 40,3300,'+', 720, 5, 5, 750,'+', 23976,'p', 64:27, 0x1, 65),//1280 x 720p @23.98/24 (Format 65) EIA_TIMING(1280,2420, 40,3960,'+', 720, 5, 5, 750,'+', 25000,'p', 64:27, 0x1, 66),//1280 x 720p @25 (Format 66) EIA_TIMING(1280,1760, 40,3300,'+', 720, 5, 5, 750,'+', 29970,'p', 64:27, 0x1, 67),//1280 x 720p @29.97/30 (Format 67) EIA_TIMING(1280, 440, 40,1980,'+', 720, 5, 5, 750,'+', 50000,'p', 64:27, 0x1, 68),//1280 x 720p @50 (Format 68) EIA_TIMING(1280, 110, 40,1650,'+', 720, 5, 5, 750,'+', 59940,'p', 64:27, 0x1, 69),//1280 x 720p @59.94/60 (Format 69) EIA_TIMING(1280, 440, 40,1980,'+', 720, 5, 5, 750,'+',100000,'p', 64:27, 0x1, 70),//1280 x 720p @100 (Format 70) EIA_TIMING(1280, 110, 40,1650,'+', 720, 5, 5, 750,'+',119880,'p', 64:27, 0x1, 71),//1280 x 720p @119.88/120 (Format 71) EIA_TIMING(1920, 638, 44,2750,'+',1080, 4, 5,1125,'+', 23976,'p', 64:27, 0x1, 72),//1920 x1080p @23.98/24 (Format 72) EIA_TIMING(1920, 528, 44,2640,'+',1080, 4, 5,1125,'+', 25000,'p', 64:27, 0x1, 73),//1920 x1080p @25 (Format 73) EIA_TIMING(1920, 88, 44,2200,'+',1080, 4, 5,1125,'+', 29970,'p', 64:27, 0x1, 74),//1920 x1080p @29.97/30 (Format 74) EIA_TIMING(1920, 528, 44,2640,'+',1080, 4, 5,1125,'+', 50000,'p', 64:27, 0x1, 75),//1920 x1080p @50 (Format 75) EIA_TIMING(1920, 88, 44,2200,'+',1080, 4, 5,1125,'+', 59940,'p', 64:27, 0x1, 76),//1920 x1080p @59.94/60 (Format 76) EIA_TIMING(1920, 528, 44,2640,'+',1080, 4, 5,1125,'+',100000,'p', 64:27, 0x1, 77),//1920 x1080p @100 (Format 77) EIA_TIMING(1920, 88, 44,2200,'+',1080, 4, 5,1125,'+',119880,'p', 64:27, 0x1, 78),//1920 x1080p @119.88/120 (Format 78) EIA_TIMING(1680,1360, 40,3300,'+', 720, 5, 5, 750,'+', 23976,'p', 64:27, 0x1, 79),//1680 x 720p @23.98/24 (Format 79) EIA_TIMING(1680,1228, 40,3168,'+', 720, 5, 5, 750,'+', 25000,'p', 64:27, 0x1, 80),//1680 x 720p @25 (Format 80) EIA_TIMING(1680, 700, 40,2640,'+', 720, 5, 5, 750,'+', 29970,'p', 64:27, 0x1, 81),//1680 x 720p @29.97/30 (Format 81) EIA_TIMING(1680, 260, 40,2200,'+', 720, 5, 5, 750,'+', 50000,'p', 64:27, 0x1, 82),//1680 x 720p @50 (Format 82) EIA_TIMING(1680, 260, 40,2200,'+', 720, 5, 5, 750,'+', 59940,'p', 64:27, 0x1, 83),//1680 x 720p @59.94/60 (Format 83) EIA_TIMING(1680, 60, 40,2000,'+', 720, 5, 5, 825,'+',100000,'p', 64:27, 0x1, 84),//1680 x 720p @100 (Format 84) EIA_TIMING(1680, 60, 40,2000,'+', 720, 5, 5, 825,'+',119880,'p', 64:27, 0x1, 85),//1680 x 720p @119.88/120 (Format 85) EIA_TIMING(2560, 998, 44,3750,'+',1080, 4, 5,1100,'+', 23976,'p', 64:27, 0x1, 86),//2560 x1080p @23.98/24 (Format 86) EIA_TIMING(2560, 448, 44,3200,'+',1080, 4, 5,1125,'+', 25000,'p', 64:27, 0x1, 87),//2560 x1080p @25 (Format 87) EIA_TIMING(2560, 768, 44,3520,'+',1080, 4, 5,1125,'+', 29970,'p', 64:27, 0x1, 88),//2560 x1080p @29.97/30 (Format 88) EIA_TIMING(2560, 548, 44,3300,'+',1080, 4, 5,1125,'+', 50000,'p', 64:27, 0x1, 89),//2560 x1080p @50 (Format 89) EIA_TIMING(2560, 248, 44,3000,'+',1080, 4, 5,1100,'+', 59940,'p', 64:27, 0x1, 90),//2560 x1080p @59.94/60 (Format 90) EIA_TIMING(2560, 218, 44,2970,'+',1080, 4, 5,1250,'+',100000,'p', 64:27, 0x1, 91),//2560 x1080p @100 (Format 91) EIA_TIMING(2560, 548, 44,3300,'+',1080, 4, 5,1250,'+',119880,'p', 64:27, 0x1, 92),//2560 x1080p @119.88/120 (Format 92) EIA_TIMING(3840,1276, 88,5500,'+',2160, 8,10,2250,'+', 23976,'p', 16:9, 0x1, 93),//3840 x2160p @23.98/24 (Format 93) EIA_TIMING(3840,1056, 88,5280,'+',2160, 8,10,2250,'+', 25000,'p', 16:9, 0x1, 94),//3840 x2160p @25 (Format 94) EIA_TIMING(3840, 176, 88,4400,'+',2160, 8,10,2250,'+', 29970,'p', 16:9, 0x1, 95),//3840 x2160p @29.97/30 (Format 95) EIA_TIMING(3840,1056, 88,5280,'+',2160, 8,10,2250,'+', 50000,'p', 16:9, 0x1, 96),//3840 x2160p @50 (Format 96) EIA_TIMING(3840, 176, 88,4400,'+',2160, 8,10,2250,'+', 59940,'p', 16:9, 0x1, 97),//3840 x2160p @59.94/60 (Format 97) EIA_TIMING(4096,1020, 88,5500,'+',2160, 8,10,2250,'+', 23976,'p',256:135, 0x1, 98),//4096 x2160p @23.98/24 (Format 98) EIA_TIMING(4096, 968, 88,5280,'+',2160, 8,10,2250,'+', 25000,'p',256:135, 0x1, 99),//4096 x2160p @25 (Format 99) EIA_TIMING(4096, 88, 88,4400,'+',2160, 8,10,2250,'+', 29970,'p',256:135, 0x1,100),//4096 x2160p @29.97/30 (Format 100) EIA_TIMING(4096, 968, 88,5280,'+',2160, 8,10,2250,'+', 50000,'p',256:135, 0x1,101),//4096 x2160p @50 (Format 101) EIA_TIMING(4096, 88, 88,4400,'+',2160, 8,10,2250,'+', 59940,'p',256:135, 0x1,102),//4096 x2160p @59.94/60 (Format 102) EIA_TIMING(3840,1276, 88,5500,'+',2160, 8,10,2250,'+', 23976,'p', 64:27, 0x1,103),//3840 x2160p @23.98/24 (Format 103) EIA_TIMING(3840,1056, 88,5280,'+',2160, 8,10,2250,'+', 25000,'p', 64:27, 0x1,104),//3840 x2160p @25 (Format 104) EIA_TIMING(3840, 176, 88,4400,'+',2160, 8,10,2250,'+', 29970,'p', 64:27, 0x1,105),//3840 x2160p @29.97/30 (Format 105) EIA_TIMING(3840,1056, 88,5280,'+',2160, 8,10,2250,'+', 50000,'p', 64:27, 0x1,106),//3840 x2160p @50 (Format 106) EIA_TIMING(3840, 176, 88,4400,'+',2160, 8,10,2250,'+', 59940,'p', 64:27, 0x1,107),//3840 x2160p @59.94/60 (Format 107) // VIC 108-127 timings are from CTA-861-G_FINAL_revised_2018_Errata_2.pdf EIA_TIMING(1280, 960, 40, 2500,'+', 720, 5, 5, 750,'+', 47950,'p', 16:9, 0x1,108),//1280 x 720p @47.95/48 (Format 108) EIA_TIMING(1280, 960, 40, 2500,'+', 720, 5, 5, 750,'+', 47950,'p', 64:27, 0x1,109),//1280 x 720p @47.95/48 (Format 109) EIA_TIMING(1680, 810, 40, 2750,'+', 720, 5, 5, 750,'+', 47950,'p', 64:27, 0x1,110),//1680 x 720p @47.95/48 (Format 110) EIA_TIMING(1920, 638, 44, 2750,'+',1080, 4, 5,1125,'+', 47950,'p', 16:9, 0x1,111),//1920 x 1080p @47.95/48 (Format 111) EIA_TIMING(1920, 638, 44, 2750,'+',1080, 4, 5,1125,'+', 47950,'p', 64:27, 0x1,112),//1920 x 1080p @47.95/48 (Format 112) EIA_TIMING(2560, 998, 44, 3750,'+',1080, 4, 5,1100,'+', 47950,'p', 64:27, 0x1,113),//2560 x 1080p @47.95/48 (Format 113) EIA_TIMING(3840,1276, 88, 5500,'+',2160, 8,10,2250,'+', 47950,'p', 16:9, 0x1,114),//3840 x 2160p @47.95/48 (Format 114) EIA_TIMING(4096,1020, 88, 5500,'+',2160, 8,10,2250,'+', 47950,'p',256:135, 0x1,115),//4096 x 2160p @47.95/48 (Format 115) EIA_TIMING(3840,1276, 88, 5500,'+',2160, 8,10,2250,'+', 47950,'p', 64:27, 0x1,116),//3840 x 2160p @47.95/48 (Format 116) EIA_TIMING(3840,1056, 88, 5280,'+',2160, 8,10,2250,'+',100000,'p', 16:9, 0x1,117),//3840 x 2160p @100 (Format 117) EIA_TIMING(3840, 176, 88, 4400,'+',2160, 8,10,2250,'+',119880,'p', 16:9, 0x1,118),//3840 x 2160p @119.88/120 (Format 118) EIA_TIMING(3840,1056, 88, 5280,'+',2160, 8,10,2250,'+',100000,'p', 64:27, 0x1,119),//3840 x 2160p @100 (Format 119) EIA_TIMING(3840, 176, 88, 4400,'+',2160, 8,10,2250,'+',119880,'p', 64:27, 0x1,120),//3840 x 2160p @119.88/120 (Format 120) EIA_TIMING(5120,1996, 88, 7500,'+',2160, 8,10,2200,'+', 23976,'p', 64:27, 0x1,121),//5120 x 2160p @23.98/24 (Format 121) EIA_TIMING(5120,1696, 88, 7200,'+',2160, 8,10,2200,'+', 25000,'p', 64:27, 0x1,122),//5120 x 2160p @25 (Format 122) EIA_TIMING(5120, 664, 88, 6000,'+',2160, 8,10,2200,'+', 29970,'p', 64:27, 0x1,123),//5120 x 2160p @29.97/30 (Format 123) EIA_TIMING(5120, 746, 88, 6250,'+',2160, 8,10,2475,'+', 47950,'p', 64:27, 0x1,124),//5120 x 2160p @47.95/48 (Format 124) EIA_TIMING(5120,1096, 88, 6600,'+',2160, 8,10,2250,'+', 50000,'p', 64:27, 0x1,125),//5120 x 2160p @50 (Format 125) EIA_TIMING(5120, 164, 88, 5500,'+',2160, 8,10,2250,'+', 59940,'p', 64:27, 0x1,126),//5120 x 2160p @59.94/60 (Format 126) EIA_TIMING(5120,1096, 88, 6600,'+',2160, 8,10,2250,'+',100000,'p', 64:27, 0x1,127),//5120 x 2160p @100 (Format 127) // VIC 128-192 are Forbidden and should be never used. But to simplify the SVD access, put a default timing here. // We can remove these after adding a function to access CEA Timings. EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 128) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 129) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 130) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 131) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 132) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 133) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 134) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 135) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 136) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 137) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 138) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 139) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 140) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 141) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 142) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 143) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 144) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 145) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 146) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 147) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 148) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 149) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 150) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 151) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 152) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 153) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 154) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 155) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 156) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 157) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 158) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 159) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 160) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 161) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 162) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 163) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 164) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 165) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 166) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 167) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 168) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 169) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 170) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 171) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 172) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 173) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 174) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 175) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 176) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 177) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 178) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 179) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 180) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 181) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 182) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 183) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 184) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 185) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 186) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 187) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 188) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 189) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 190) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 191) EIA_TIMING( 640, 16, 96, 800,'-', 480,10,2, 525,'-', 59940,'p', 4:3, 0x1, 0),//640 x 480p @59.94/60 //Forbidden (Format 192) // VIC 193-219 timings are from CTA-861-G_FINAL_revised_2018_Errata_2.pdf EIA_TIMING( 5120, 164, 88, 5500,'+',2160, 8,10,2250,'+',120000,'p', 64:27,0x1,193),// 5120 x 2160p @119.88/120 (Format 193) EIA_TIMING( 7680,2552,176,11000,'+',4320,16,20,4500,'+', 23976,'p', 16:9,0x1,194),// 7680 x 4320p @23.98/24 (Format 194) EIA_TIMING( 7680,2352,176,10800,'+',4320,16,20,4400,'+', 25000,'p', 16:9,0x1,195),// 7680 x 4320p @25 (Format 195) EIA_TIMING( 7680, 552,176, 9000,'+',4320,16,20,4400,'+', 29970,'p', 16:9,0x1,196),// 7680 x 4320p @29.97/30 (Format 196) EIA_TIMING( 7680,2552,176,11000,'+',4320,16,20,4500,'+', 47950,'p', 16:9,0x1,197),// 7680 x 4320p @47.95/48 (Format 197) EIA_TIMING( 7680,2352,176,10800,'+',4320,16,20,4400,'+', 50000,'p', 16:9,0x1,198),// 7680 x 4320p @50 (Format 198) EIA_TIMING( 7680, 552,176, 9000,'+',4320,16,20,4400,'+', 59940,'p', 16:9,0x1,199),// 7680 x 4320p @59.94/60 (Format 199) EIA_TIMING( 7680,2112,176,10560,'+',4320,16,20,4500,'+',100000,'p', 16:9,0x1,200),// 7680 x 4320p @100 (Format 200) EIA_TIMING( 7680, 352,176, 8000,'+',4320,16,20,4500,'+',119880,'p', 16:9,0x1,201),// 7680 x 4320p @119.88/120 (Format 201) EIA_TIMING( 7680,2552,176,11000,'+',4320,16,20,4500,'+', 23976,'p', 64:27,0x1,202),// 7680 x 4320p @23.98/24 (Format 202) EIA_TIMING( 7680,2352,176,10800,'+',4320,16,20,4400,'+', 25000,'p', 64:27,0x1,203),// 7680 x 4320p @25 (Format 203) EIA_TIMING( 7680, 552,176, 9000,'+',4320,16,20,4400,'+', 29970,'p', 64:27,0x1,204),// 7680 x 4320p @29.97/30 (Format 204) EIA_TIMING( 7680,2552,176,11000,'+',4320,16,20,4500,'+', 47950,'p', 64:27,0x1,205),// 7680 x 4320p @47.95/48 (Format 205) EIA_TIMING( 7680,2352,176,10800,'+',4320,16,20,4400,'+', 50000,'p', 64:27,0x1,206),// 7680 x 4320p @50 (Format 206) EIA_TIMING( 7680, 552,176, 9000,'+',4320,16,20,4400,'+', 59940,'p', 64:27,0x1,207),// 7680 x 4320p @59.94/60 (Format 207) EIA_TIMING( 7680,2112,176,10560,'+',4320,16,20,4500,'+',100000,'p', 64:27,0x1,208),// 7680 x 4320p @100 (Format 208) EIA_TIMING( 7680, 352,176, 8800,'+',4500,16,20,4950,'+',119880,'p', 64:27,0x1,209),// 7680 x 4320p @119.88/120 (Format 209) EIA_TIMING(10240,1492,176,12500,'+',4320,16,20,4950,'+', 23976,'p', 64:27,0x1,210),//10240 x 4320p @23.98/24 (Format 210) EIA_TIMING(10240,2492,176,13500,'+',4320,16,20,4400,'+', 25000,'p', 64:27,0x1,211),//10240 x 4320p @25 (Format 211) EIA_TIMING(10240, 288,176,11000,'+',4320,16,20,4500,'+', 29970,'p', 64:27,0x1,212),//10240 x 4320p @29.97/30 (Format 212) EIA_TIMING(10240,1492,176,12500,'+',4320,16,20,4950,'+', 47950,'p', 64:27,0x1,213),//10240 x 4320p @47.95/48 (Format 213) EIA_TIMING(10240,2492,176,13500,'+',4320,16,20,4400,'+', 44000,'p', 64:27,0x1,214),//10240 x 4320p @50 (Format 214) EIA_TIMING(10240, 288,176,11000,'+',4320,16,20,4500,'+', 59940,'p', 64:27,0x1,215),//10240 x 4320p @59.94/60 (Format 215) EIA_TIMING(10240,2192,176,13200,'+',4320,16,20,4500,'+',100000,'p', 64:27,0x1,216),//10240 x 4320p @100 (Format 216) EIA_TIMING(10240, 288,176,11000,'+',4320,16,20,4500,'+',119880,'p', 64:27,0x1,217),//10240 x 4320p @119.88/120 (Format 217) EIA_TIMING( 4096, 800, 88, 5280,'+',2160, 8,10,2250,'+',100000,'p',256:135,0x1,218),// 4096 x 2160p @100 (Format 218) EIA_TIMING( 4096, 88, 88, 4400,'+',2160, 8,10,2250,'+',119880,'p',256:135,0x1,219),// 4096 x 2160p @119.88/120 (Format 219) // 220-255 Reserved for the Future // the end EIA_TIMING(0,0,0,0,'-',0,0,0,0,'-',0,'p',4:3,0,0) }; static NvU32 MAX_CEA861B_FORMAT = sizeof(EIA861B)/sizeof(EIA861B[0]) - 1; static const NvU32 EIA861B_DUAL_ASPECT_VICS[][2] = { { 2, 3 }, // 720x480p 59.94Hz/60Hz { 4, 69 }, // 1280x720p 59.94Hz/60Hz { 6, 7 }, // 720(1440)x480i 59.94Hz/60Hz { 8, 9 }, // 720(1440)x240p 59.94Hz/60Hz { 10, 11 }, // 2880x480i 59.94Hz/60Hz { 12, 13 }, // 2880x240p 59.94Hz/60Hz { 14, 15 }, // 1440x480p 59.94Hz/60Hz { 16, 76 }, // 1920x1080p 59.94Hz/60Hz { 17, 18 }, // 720x576p 50Hz { 19, 68 }, // 1280x720p 50Hz { 21, 22 }, // 720(1440)x576i 50Hz { 23, 24 }, // 720(1440)x288p 50Hz { 25, 26 }, // 2880x576i 50Hz { 27, 28 }, // 2880x288p 50Hz { 29, 30 }, // 1440x576p 50Hz { 31, 75 }, // 1920x1080p 50Hz { 32, 72 }, // 1920x1080p 23.98Hz/24Hz { 33, 73 }, // 1920x1080p 25Hz { 34, 74 }, // 1920x1080p 29.97Hz/30Hz { 35, 36 }, // 2880x480p 59.94Hz/60Hz { 37, 38 }, // 2880x576p 50Hz { 41, 70 }, // 1280x720p 100Hz { 42, 43 }, // 720x576p 100Hz { 44, 45 }, // 720(1440)x576i 100Hz { 47, 71 }, // 1280x720p 119.88/120Hz { 48, 49 }, // 720x480p 119.88/120Hz { 50, 51 }, // 720(1440)x480i 119.88/120Hz { 52, 53 }, // 720x576p 200Hz { 54, 55 }, // 720(1440)x576i 200Hz { 56, 57 }, // 720x480p 239.76/240Hz { 58, 59 }, // 720(1440)x480i 239.76/240Hz { 60, 65 }, // 1280x720p 23.98Hz/24Hz { 61, 66 }, // 1280x720p 25Hz { 62, 67 }, // 1280x720p 29.97Hz/30Hz { 63, 78 }, // 1920x1080p 119.88/120Hz { 64, 77 }, // 1920x1080p 100Hz { 93, 103 }, // 3840x2160p 23.98Hz/24Hz { 94, 104 }, // 3840x2160p 25Hz { 95, 105 }, // 3840x2160p 29.97Hz/30Hz { 96, 106 }, // 3840x2160p 50Hz { 97, 107 }, // 3840x2160p 59.94Hz/60Hz }; static NvU32 MAX_EIA861B_DUAL_ASPECT_VICS = sizeof(EIA861B_DUAL_ASPECT_VICS) / sizeof(EIA861B_DUAL_ASPECT_VICS[0]); static const NVT_TIMING PSF_TIMING[]= { NVT_TIMING( 1920,600, 88,2750,'+', 540, 2,5,562,'+',47952,'i',16:9, 0x1, 1, "ITU-R BT.709-5:1080i/24Psf"),//1920x1080i @47.952Hz | 24/PsF | ITU-R BT.709-5 NVT_TIMING( 1920,488, 88,2640,'+', 540, 2,5,562,'+',49950,'i',16:9, 0x1, 2, "ITU-R BT.709-5:1080i/25Psf"),//1920x1080i @49.950Hz | 25/PsF | ITU-R BT.709-5 // the end EIA_TIMING(0,0,0,0,'-',0,0,0,0,'-',0,'p',4:3,0,0) }; static NvU32 MAX_PSF_FORMAT = sizeof(PSF_TIMING)/sizeof(PSF_TIMING[0]) - 1; static const NVT_TIMING HDMI_EXT_4Kx2K_TIMING[]= { HDMI_EXT_TIMING( 3840, 176, 88,4400,'+', 2160, 8,10,2250,'+',29970,'p',16:9, 0x1, NVT_HDMI_VS_BYTE5_HDMI_VIC_4Kx2Kx30Hz, "HDMI EXT: 3840x2160x29.97/30hz"),//3840x2160 @29.97/30Hz VIC: 0x01 HDMI_EXT_TIMING( 3840,1056, 88,5280,'+', 2160, 8,10,2250,'+',25000,'p',16:9, 0x1, NVT_HDMI_VS_BYTE5_HDMI_VIC_4Kx2Kx25Hz, "HDMI EXT: 3840x2160x25hz"), //3840x2160 @25Hz VIC: 0x02 HDMI_EXT_TIMING( 3840,1276, 88,5500,'+', 2160, 8,10,2250,'+',23976,'p',16:9, 0x1, NVT_HDMI_VS_BYTE5_HDMI_VIC_4Kx2Kx24Hz, "HDMI EXT: 3840x2160x23.98/24hz"),//3840x2160 @23.98/24Hz VIC: 0x03 HDMI_EXT_TIMING( 4096,1020, 88,5500,'+', 2160, 8,10,2250,'+',24000,'p',16:9, 0x1, NVT_HDMI_VS_BYTE5_HDMI_VIC_4Kx2Kx24Hz_SMPTE, "HDMI EXT: 4096x2160x24hzSmpte"), //4096x2160 @24Hz VIC: 0x04 // the end EIA_TIMING(0,0,0,0,'-',0,0,0,0,'-',0,'p',4:3,0,0) }; static NvU32 MAX_HDMI_EXT_4Kx2K_FORMAT = sizeof(HDMI_EXT_4Kx2K_TIMING)/sizeof(HDMI_EXT_4Kx2K_TIMING[0]) - 1; // HDMI 1.4a mandatory 3D video formats. // From HDMI 1.4a specification page 147 of 201, table 8-15. And HDMI 1.4a Complaince test specification page 190. static const HDMI3DDETAILS HDMI_MANDATORY_3D_FORMATS[] = { {32, NVT_HDMI_3D_SUPPORTED_FRAMEPACK_MASK | NVT_HDMI_3D_SUPPORTED_TOPBOTTOM_MASK, 0}, // 1920 x 1080p @ 24 Hz { 4, NVT_HDMI_3D_SUPPORTED_FRAMEPACK_MASK | NVT_HDMI_3D_SUPPORTED_TOPBOTTOM_MASK, 0}, // 1280 x 720p @ 60 Hz {19, NVT_HDMI_3D_SUPPORTED_FRAMEPACK_MASK | NVT_HDMI_3D_SUPPORTED_TOPBOTTOM_MASK, 0}, // 1280 x 720p @ 50 Hz { 5, NVT_HDMI_3D_SUPPORTED_SIDEBYSIDEHALF_MASK, NVT_HDMI_VS_BYTE_OPT1_HDMI_3DEX_SSH}, // 1920 x 1080i @ 60 Hz {20, NVT_HDMI_3D_SUPPORTED_SIDEBYSIDEHALF_MASK, NVT_HDMI_VS_BYTE_OPT1_HDMI_3DEX_SSH} // 1920 x 1080i @ 50 Hz }; static NvU32 MAX_HDMI_MANDATORY_3D_FORMAT = sizeof(HDMI_MANDATORY_3D_FORMATS) / sizeof(HDMI_MANDATORY_3D_FORMATS[0]); static const NVT_VIDEO_INFOFRAME DEFAULT_VIDEO_INFOFRAME = {/*header*/2,2,13, /*byte1*/0, /*byte2*/0x8, /*byte3*/0, /*byte4*/0, /*byte5*/0, /*byte6~13*/0,0,0,0,0,0,0,0}; static const NVT_AUDIO_INFOFRAME DEFAULT_AUDIO_INFOFRAME = {/*header*/4,1,10, /*byte1*/0, /*byte2*/0, /*byte3*/0, /*byte*/0, /*byte5*/0, /*byte6~10*/0,0,0,0,0}; static const NVT_VENDOR_SPECIFIC_INFOFRAME DEFAULT_VENDOR_SPECIFIC_INFOFRAME = {/*header*/{0x01,1,6}, {/*byte1*/3, /*byte2*/0x0c, /*byte3*/0, /*byte4*/0, /*byte5*/0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}; // parse the 861 detailed timing info CODE_SEGMENT(PAGE_DD_CODE) void parse861ExtDetailedTiming(NvU8 *pEdidExt, NvU8 basicCaps, NVT_EDID_INFO *pInfo) { NvU32 count = 0; EIA861EXTENSION *pEIA861 = (EIA861EXTENSION *) pEdidExt; DETAILEDTIMINGDESCRIPTOR *pDTD; NVT_TIMING newTiming; // sanity check for CEA ext block if ((pEIA861->tag != 0x2) || (0 == pEIA861->offset) || (NVT_CEA861_REV_NONE == pEIA861->revision)) { // no CEA ext block, return return; } // Get all detailed timings in CEA ext block pDTD = (DETAILEDTIMINGDESCRIPTOR *)&pEdidExt[pEIA861->offset]; while((NvU8 *)pDTD + sizeof(DETAILEDTIMINGDESCRIPTOR) < (pEdidExt + sizeof(EDIDV1STRUC) - 1) && pDTD->wDTPixelClock != 0) { NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming)); if (parseEdidDetailedTimingDescriptor((NvU8 *)pDTD, &newTiming) == NVT_STATUS_SUCCESS) { NVT_SNPRINTF((char *)newTiming.etc.name, sizeof(newTiming.etc.name), "CTA-861Long:%5dx%4dx%3d.%03dHz/%s", (int)newTiming.HVisible, (int)((newTiming.interlaced ? 2 : 1) * newTiming.VVisible), (int)newTiming.etc.rrx1k/1000, (int)newTiming.etc.rrx1k%1000, (newTiming.interlaced ? "I":"P")); newTiming.etc.name[sizeof(newTiming.etc.name)-1] = '\0'; newTiming.etc.status = NVT_STATUS_EDID_EXT_DTDn(++count); if (!assignNextAvailableTiming(pInfo, &newTiming)) { break; } } pDTD ++; } } // parse the 861B short timing descriptor CODE_SEGMENT(PAGE_DD_CODE) void parse861bShortTiming(NVT_EDID_CEA861_INFO *pExt861, void *pRawInfo, NVT_CTA861_ORIGIN flag) { NvU32 i; NvU32 vic, bytePos, bitPos; NVT_TIMING newTiming; NVT_HDMI_FORUM_INFO *pHfvs = NULL; NVT_EDID_INFO *pInfo = NULL; NVT_DISPLAYID_2_0_INFO *pDisplayID20 = NULL; NvU8 *pVic = pExt861->video; NvU32 total_svd = pExt861->total_svd; NvU8 *pYuv420Map = pExt861->valid.y420cmdb ? pExt861->map_y420cmdb : NULL; NvU8 yuv420MapCount = pExt861->total_y420cmdb; if (flag == FROM_CTA861_EXTENSION || flag == FROM_DISPLAYID_13_DATA_BLOCK) { pInfo = (NVT_EDID_INFO *)pRawInfo; pHfvs = &pInfo->hdmiForumInfo; } else if (flag == FROM_DISPLAYID_20_DATA_BLOCK) { pDisplayID20 = (NVT_DISPLAYID_2_0_INFO *)pRawInfo; pHfvs = &pDisplayID20->vendor_specific.hfvs; } else { return; } for (i = 0; i < total_svd; i++) { vic = NVT_GET_CTA_8BIT_VIC(pVic[i]); if (vic == 0 || vic > MAX_CEA861B_FORMAT) continue; // assign corresponding CEA format's timing from pre-defined CE timing table, EIA861B newTiming = EIA861B[vic-1]; newTiming.etc.status = NVT_STATUS_EDID_861STn(vic); // set CEA format to location of _CEA_FORMAT. _CEA_FORMAT isn't set in pre-defined CE timing from // EIA861B table if (NVT_GET_TIMING_STATUS_SEQ(newTiming.etc.status) != NVT_CEA861_640X480P_59940HZ_4X3) { // Although IT 640x480 video timing has a CE id, it is not a CE timing. See 3.1 // "General Video Format Requirements" section in CEA-861-E spec NVT_SET_CEA_FORMAT(newTiming.etc.status, NVT_GET_TIMING_STATUS_SEQ(newTiming.etc.status)); } // calculate the pixel clock newTiming.pclk = RRx1kToPclk(&newTiming); if ((vic <= 64) && (pVic[i] & NVT_CTA861_VIDEO_NATIVE_MASK)) { NVT_SET_NATIVE_TIMING_FLAG(newTiming.etc.status); } NVT_SNPRINTF((char *)newTiming.etc.name, sizeof(newTiming.etc.name), "CTA-861G:#%3d:%5dx%4dx%3d.%03dHz/%s", (int)vic, (int)newTiming.HVisible, (int)((newTiming.interlaced ? 2 : 1)*newTiming.VVisible), (int)newTiming.etc.rrx1k/1000, (int)newTiming.etc.rrx1k%1000, (newTiming.interlaced ? "I":"P")); newTiming.etc.name[sizeof(newTiming.etc.name)-1] = '\0'; // if yuv420 is supported in the video SVDs, it is indicated by CMDB bitmap bytePos = i / (8 * sizeof(NvU8)); if (bytePos < yuv420MapCount) { bitPos = 1 << (i % (8 * sizeof(NvU8))); if (pYuv420Map[bytePos] & bitPos) { // pHfvs->dcXXX are only for YCbCr420; when bitPos is set, 8bpc yuv420 always supported UPDATE_BPC_FOR_COLORFORMAT(newTiming.etc.yuv420, 0, 1, pHfvs->dc_30bit_420, pHfvs->dc_36bit_420, 0, pHfvs->dc_48bit_420); } } // Y420CMDB with L == 1, implies yuv420MapCount == 0 but all SVDs support 420 if (pYuv420Map && yuv420MapCount == 0) { UPDATE_BPC_FOR_COLORFORMAT(newTiming.etc.yuv420, 0, 1, pHfvs->dc_30bit_420, pHfvs->dc_36bit_420, 0, pHfvs->dc_48bit_420); } if (flag == FROM_CTA861_EXTENSION || flag == FROM_DISPLAYID_13_DATA_BLOCK) { if (!assignNextAvailableTiming(pInfo, &newTiming)) { break; } } else if (flag == FROM_DISPLAYID_20_DATA_BLOCK) { newTiming.etc.flag |= NVT_FLAG_DISPLAYID_2_0_TIMING; if (!assignNextAvailableDisplayId20Timing(pDisplayID20, &newTiming)) { break; } } } } // parse the 861B short Yuv420 timing descriptor CODE_SEGMENT(PAGE_DD_CODE) void parse861bShortYuv420Timing(NVT_EDID_CEA861_INFO *pExt861, void *pRawInfo, NVT_CTA861_ORIGIN flag) { NvU32 i; NvU8 vic; NVT_TIMING newTiming; NVT_HDMI_FORUM_INFO *pHfvs = NULL; NVT_EDID_INFO *pInfo = NULL; NVT_DISPLAYID_2_0_INFO *pDisplayID20 = NULL; NvU8 *pYuv420Vic = pExt861->svd_y420vdb; NvU32 total_y420vdb = pExt861->total_y420vdb; NvU8 *pVdb = pExt861->video; NvU32 total_svd = pExt861->total_svd; NvU32 total_timings = 0; if (flag == FROM_CTA861_EXTENSION || flag == FROM_DISPLAYID_13_DATA_BLOCK) { pInfo = (NVT_EDID_INFO *)pRawInfo; pHfvs = &pInfo->hdmiForumInfo; total_timings = pInfo->total_timings; } else if (flag == FROM_DISPLAYID_20_DATA_BLOCK) { pDisplayID20 = (NVT_DISPLAYID_2_0_INFO *)pRawInfo; pHfvs = &pDisplayID20->vendor_specific.hfvs; total_timings = pDisplayID20->total_timings; } else { return; } if (total_timings == 0) { return; } for (i = 0; i < total_y420vdb; i++) { vic = NVT_GET_CTA_8BIT_VIC(pYuv420Vic[i]); if (vic == 0 || vic > MAX_CEA861B_FORMAT) continue; // assign corresponding CEA format's timing from pre-defined CE timing table, EIA861B newTiming = EIA861B[vic-1]; // if yuv420 is supported in the video SVDs, it is indicated by yuv420vdb if(total_svd > 0) { NvU8 idx, j; NvBool bFound = NV_FALSE; for (idx=0; idx < total_svd; idx++) { if (pVdb[idx] == vic) { for (j=0; j < total_timings; j++) { NVT_TIMING *timing = NULL; if (flag == FROM_CTA861_EXTENSION || flag == FROM_DISPLAYID_13_DATA_BLOCK) { timing = &pInfo->timing[j]; } else if (flag == FROM_DISPLAYID_20_DATA_BLOCK) { timing = &pDisplayID20->timing[j]; } if (NvTiming_IsTimingExactEqual(timing, &newTiming)) { bFound = NV_TRUE; // we found one in pExt861->video[]. pHfvs->dcXXX are only for YCbCr420, so we can support: // 1. 8bpc yuv420 always supported. // 2. only add yuv420 and its deep colour caps into Video Data Block UPDATE_BPC_FOR_COLORFORMAT(timing->etc.yuv420, 0, 1, pHfvs->dc_30bit_420, pHfvs->dc_36bit_420, 0, pHfvs->dc_48bit_420); break; } } } } if (bFound) continue; } newTiming.etc.status = NVT_STATUS_EDID_861STn(vic); // set CEA format to location of _CEA_FORMAT. _CEA_FORMAT isn't set in pre-defined CE timing from // EIA861B table if (NVT_GET_TIMING_STATUS_SEQ(newTiming.etc.status) != NVT_CEA861_640X480P_59940HZ_4X3) { // Although IT 640x480 video timing has a CE id, it is not a CE timing. See 3.1 // "General Video Format Requirements" section in CEA-861-E spec NVT_SET_CEA_FORMAT(newTiming.etc.status, NVT_GET_TIMING_STATUS_SEQ(newTiming.etc.status)); } // calculate the pixel clock newTiming.pclk = RRx1kToPclk(&newTiming); // From CTA-861-F: By default, Y420VDB SVDs, when present in the EDID, shall be less preferred than all regular Video Data Block SVDs. // So it should use normal VIC code without native flag. //if ((vic <= 64) && (pVic[i] & NVT_CTA861_VIDEO_NATIVE_MASK)) //{ // NVT_SET_NATIVE_TIMING_FLAG(newTiming.etc.status); //} NVT_SNPRINTF((char *)newTiming.etc.name, sizeof(newTiming.etc.name), "CTA-861G:#%3d:%5dx%4dx%3d.%03dHz/%s", (int)vic, (int)newTiming.HVisible, (int)((newTiming.interlaced ? 2 : 1)*newTiming.VVisible), (int)newTiming.etc.rrx1k/1000, (int)newTiming.etc.rrx1k%1000, (newTiming.interlaced ? "I":"P")); newTiming.etc.name[sizeof(newTiming.etc.name)-1] = '\0'; // update supported color space; any VICs enumerated in the Y420VDB are yuv420 only modes // update 8bpc supported color space; other bpc updated once VSDB is parsed // pHfvs->dcXXX are only for YCbCr420; when Vic enumerated here, 8bpc yuv420 always supported UPDATE_BPC_FOR_COLORFORMAT(newTiming.etc.yuv420, 0, 1, pHfvs->dc_30bit_420, pHfvs->dc_36bit_420, 0, pHfvs->dc_48bit_420); if (flag == FROM_CTA861_EXTENSION || flag == FROM_DISPLAYID_13_DATA_BLOCK) { if (!assignNextAvailableTiming(pInfo, &newTiming)) { break; } } else if (flag == FROM_DISPLAYID_20_DATA_BLOCK) { newTiming.etc.flag |= NVT_FLAG_DISPLAYID_2_0_TIMING; if (assignNextAvailableDisplayId20Timing(pDisplayID20, &newTiming)) { break; } } } } // Currently, we only focus on the particular application in CEA861-F spec described // "One particular application is a Sink that prefers a Video Format that is not listed as an SVD in a VDB // but instead listed in a YCBCR 4:2:0 Video Data Block" CODE_SEGMENT(PAGE_DD_CODE) void parse861bShortPreferredTiming(NVT_EDID_CEA861_INFO *pExt861, void *pRawInfo, NVT_CTA861_ORIGIN flag) { NvU32 isMatch,i,j = 0; NVT_TIMING preferTiming; NVT_EDID_INFO *pInfo = NULL; NVT_DISPLAYID_2_0_INFO *pDisplayID20 = NULL; NvU8 *pSvr = pExt861->svr_vfpdb; NvU8 totalSvr = pExt861->total_vfpdb; NvU8 kth = 0; NvU8 extKth = 0; NvU8 DTDCount = 0; NvU8 extDTDCount = 0; if (flag == FROM_CTA861_EXTENSION || flag == FROM_DISPLAYID_13_DATA_BLOCK) { pInfo = (NVT_EDID_INFO *)pRawInfo; } else if (flag == FROM_DISPLAYID_20_DATA_BLOCK) { pDisplayID20 = (NVT_DISPLAYID_2_0_INFO *)pRawInfo; } else { return; } // finding all the DTD if (flag == FROM_CTA861_EXTENSION) { for (j = 0; j < pInfo->total_timings; j++) { if (NVT_IS_DTD(pInfo->timing[j].etc.status)) { DTDCount++; } else if (NVT_IS_EXT_DTD(pInfo->timing[j].etc.status)) { extDTDCount++; } } } // TODO : this only handle single SVR right now for (i = 0; i < totalSvr; i++) { NvU8 svr = pSvr[i]; NvU8 vic = 0; if (svr == 0 || svr == 128 || (svr >= 161 && svr <= 192) || svr == 255) continue; // Kth 18bytes DTD in the EDID if (svr >= 129 && svr <= 144) { kth = svr - 128; // only base EDID and CTA861 can support 18bytes if (flag == FROM_CTA861_EXTENSION) { for (j = 0; j < pInfo->total_timings; j++) { if (kth <= DTDCount) { if (NVT_IS_DTDn(pInfo->timing[j].etc.status, kth)) { pInfo->timing[j].etc.flag |= NVT_FLAG_CEA_PREFERRED_TIMING; break; } } else { extKth = kth - DTDCount; if (NVT_IS_EXT_DTDn(pInfo->timing[j].etc.status, extKth)) { pInfo->timing[j].etc.flag |= NVT_FLAG_CEA_PREFERRED_TIMING; break; } } } } } else if (svr >= 145 && svr <= 160) { // TODO : Interpret as the Nth 20-byte DTD or 6- or 7-byte CVT-based descriptor, // where N = SVR – 144 (for N = 1 to 16) break; } else if (svr == 254) { // TODO : Interpret as the timing format indicated by the first code of the first T8VTDB break; } else // assign corresponding CEA format's timing from pre-defined CE timing table, EIA861B { // ( SVR >= 1 and SVR <= 127) and (SVR >= 193 and SVR <= 253) vic = NVT_GET_CTA_8BIT_VIC(svr); preferTiming = EIA861B[vic-1]; if (flag == FROM_CTA861_EXTENSION || flag == FROM_DISPLAYID_13_DATA_BLOCK) { for (j = 0; j < pInfo->total_timings; j++) { isMatch = NvTiming_IsTimingExactEqual(&pInfo->timing[j], &preferTiming); if (isMatch && (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[j].etc.status) == NVT_TYPE_EDID_861ST)) { pInfo->timing[j].etc.flag |= NVT_FLAG_CEA_PREFERRED_TIMING; break; } } } else if (flag == FROM_DISPLAYID_20_DATA_BLOCK) { for (j = 0; j < pDisplayID20->total_timings; j++) { isMatch = NvTiming_IsTimingExactEqual(&pDisplayID20->timing[j], &preferTiming); if (isMatch && (NVT_GET_TIMING_STATUS_TYPE(pDisplayID20->timing[j].etc.status) == NVT_TYPE_EDID_861ST)) { pDisplayID20->timing[j].etc.flag |= NVT_FLAG_CEA_PREFERRED_TIMING | NVT_FLAG_DISPLAYID_2_0_TIMING; break; } } } } } } CODE_SEGMENT(PAGE_DD_CODE) void parseCea861HdrStaticMetadataDataBlock(NVT_EDID_CEA861_INFO *pExt861, void *pRawInfo, NVT_CTA861_ORIGIN flag) { NVT_EDID_INFO *pInfo = NULL; NVT_DISPLAYID_2_0_INFO *pDisplayID20 = NULL; NVT_HDR_STATIC_METADATA *pHdrInfo = NULL; if (flag == FROM_CTA861_EXTENSION || flag == FROM_DISPLAYID_13_DATA_BLOCK) { pInfo = (NVT_EDID_INFO *)pRawInfo; pHdrInfo = &pInfo->hdr_static_metadata_info; } else if (flag == FROM_DISPLAYID_20_DATA_BLOCK) { pDisplayID20 = (NVT_DISPLAYID_2_0_INFO *)pRawInfo; pHdrInfo = &pDisplayID20->cta.hdrInfo; } else { return; } if (pExt861 == NULL || pHdrInfo == NULL) { return; } // Parse the EOTF capability information. It's possible to have multiple EOTF if (pExt861->hdr_static_metadata.byte1 & NVT_CEA861_EOTF_GAMMA_SDR) { pHdrInfo->supported_eotf.trad_gamma_sdr_eotf = 1; } if (pExt861->hdr_static_metadata.byte1 & NVT_CEA861_EOTF_GAMMA_HDR) { pHdrInfo->supported_eotf.trad_gamma_hdr_eotf = 1; } if (pExt861->hdr_static_metadata.byte1 & NVT_CEA861_EOTF_SMPTE_ST2084) { pHdrInfo->supported_eotf.smpte_st_2084_eotf = 1; } if (pExt861->hdr_static_metadata.byte1 & NVT_CEA861_EOTF_FUTURE) { pHdrInfo->supported_eotf.future_eotf = 1; } // Parse the static metadata descriptor if (pExt861->hdr_static_metadata.byte2) { pHdrInfo->static_metadata_type = 1; } else { pHdrInfo->static_metadata_type = 0; } pHdrInfo->max_cll = pExt861->hdr_static_metadata.byte3 & NVT_CEA861_MAX_CLL_MASK; pHdrInfo->max_fall = pExt861->hdr_static_metadata.byte4 & NVT_CEA861_MAX_FALL_MASK; pHdrInfo->min_cll = pExt861->hdr_static_metadata.byte5 & NVT_CEA861_MIN_CLL_MASK; } CODE_SEGMENT(PAGE_DD_CODE) void parseCea861DvStaticMetadataDataBlock(NVT_EDID_CEA861_INFO *pExt861, void *pRawInfo, NVT_CTA861_ORIGIN flag) { NvU32 vsvdbVersion = 0; NVT_DV_STATIC_METADATA_TYPE0 *pDvType0 = NULL; NVT_DV_STATIC_METADATA_TYPE1 *pDvType1 = NULL; NVT_DV_STATIC_METADATA_TYPE1_1 *pvDvType1_1 = NULL; NVT_DV_STATIC_METADATA_TYPE2 *pDvType2 = NULL; NVT_EDID_INFO *pInfo = NULL; NVT_DISPLAYID_2_0_INFO *pDisplayID20 = NULL; NVT_DV_STATIC_METADATA *pDvInfo = NULL; if (pExt861 == NULL || pRawInfo == NULL) { return; } if (flag == FROM_CTA861_EXTENSION || flag == FROM_DISPLAYID_13_DATA_BLOCK) { pInfo = (NVT_EDID_INFO *)pRawInfo; pDvInfo = &pInfo->dv_static_metadata_info; } else if (flag == FROM_DISPLAYID_20_DATA_BLOCK) { pDisplayID20 = (NVT_DISPLAYID_2_0_INFO *)pRawInfo; pDvInfo = &pDisplayID20->cta.dvInfo; } else { return; } if(pExt861->vsvdb.ieee_id != NVT_CEA861_DV_IEEE_ID) { return; } //init NVMISC_MEMSET(pDvInfo, 0, sizeof(NVT_DV_STATIC_METADATA)); // copy ieee id pDvInfo->ieee_id = pExt861->vsvdb.ieee_id; vsvdbVersion = (pExt861->vsvdb.vendor_data[0] & NVT_CEA861_VSVDB_VERSION_MASK) >> NVT_CEA861_VSVDB_VERSION_MASK_SHIFT; switch (vsvdbVersion) { case 0: if (pExt861->vsvdb.vendor_data_size < sizeof(NVT_DV_STATIC_METADATA_TYPE0)) { return; } pDvType0 = (NVT_DV_STATIC_METADATA_TYPE0 *)(&pExt861->vsvdb.vendor_data); // copy the data pDvInfo->VSVDB_version = pDvType0->VSVDB_version; pDvInfo->supports_2160p60hz = pDvType0->supports_2160p60hz; pDvInfo->supports_YUV422_12bit = pDvType0->supports_YUV422_12bit; pDvInfo->supports_global_dimming = pDvType0->supports_global_dimming; pDvInfo->colorimetry = 0; // this field does not exist in type0 pDvInfo->dm_version = (pDvType0->dm_version_major << 4) | pDvType0->dm_version_minor; pDvInfo->target_min_luminance = (pDvType0->target_min_pq_11_4 << 4) | pDvType0->target_min_pq_3_0; pDvInfo->target_max_luminance = (pDvType0->target_max_pq_11_4 << 4) | pDvType0->target_max_pq_3_0; pDvInfo->cc_red_x = (pDvType0->cc_red_x_11_4 << 4) | pDvType0->cc_red_x_3_0; pDvInfo->cc_red_y = (pDvType0->cc_red_y_11_4 << 4) | pDvType0->cc_red_y_3_0; pDvInfo->cc_green_x = (pDvType0->cc_green_x_11_4 << 4) | pDvType0->cc_green_x_3_0; pDvInfo->cc_green_y = (pDvType0->cc_green_y_11_4 << 4) | pDvType0->cc_green_y_3_0; pDvInfo->cc_blue_x = (pDvType0->cc_blue_x_11_4 << 4) | pDvType0->cc_blue_x_3_0; pDvInfo->cc_blue_y = (pDvType0->cc_blue_y_11_4 << 4) | pDvType0->cc_blue_y_3_0; pDvInfo->cc_white_x = (pDvType0->cc_white_x_11_4 << 4) | pDvType0->cc_white_x_3_0; pDvInfo->cc_white_y = (pDvType0->cc_white_y_11_4 << 4) | pDvType0->cc_white_y_3_0; pDvInfo->supports_backlight_control = 0; pDvInfo->backlt_min_luma = 0; pDvInfo->interface_supported_by_sink = 0; pDvInfo->supports_10b_12b_444 = 0; break; case 1: if (pExt861->vsvdb.vendor_data_size == sizeof(NVT_DV_STATIC_METADATA_TYPE1)) { pDvType1 = (NVT_DV_STATIC_METADATA_TYPE1 *)(&pExt861->vsvdb.vendor_data); // copy the data pDvInfo->VSVDB_version = pDvType1->VSVDB_version; pDvInfo->supports_2160p60hz = pDvType1->supports_2160p60hz; pDvInfo->supports_YUV422_12bit = pDvType1->supports_YUV422_12bit; pDvInfo->dm_version = pDvType1->dm_version; pDvInfo->supports_global_dimming = pDvType1->supports_global_dimming; pDvInfo->colorimetry = pDvType1->colorimetry; pDvInfo->target_min_luminance = pDvType1->target_min_luminance; pDvInfo->target_max_luminance = pDvType1->target_max_luminance; pDvInfo->cc_red_x = pDvType1->cc_red_x; pDvInfo->cc_red_y = pDvType1->cc_red_y; pDvInfo->cc_green_x = pDvType1->cc_green_x; pDvInfo->cc_green_y = pDvType1->cc_green_y; pDvInfo->cc_blue_x = pDvType1->cc_blue_x; pDvInfo->cc_blue_y = pDvType1->cc_blue_y; pDvInfo->supports_backlight_control = 0; pDvInfo->backlt_min_luma = 0; pDvInfo->interface_supported_by_sink = 0; pDvInfo->supports_10b_12b_444 = 0; pDvInfo->cc_white_x = 0; pDvInfo->cc_white_y = 0; } else if (pExt861->vsvdb.vendor_data_size == sizeof(NVT_DV_STATIC_METADATA_TYPE1_1)) { pvDvType1_1 = (NVT_DV_STATIC_METADATA_TYPE1_1 *)(&pExt861->vsvdb.vendor_data); // copy the data pDvInfo->VSVDB_version = pvDvType1_1->VSVDB_version; pDvInfo->supports_2160p60hz = pvDvType1_1->supports_2160p60hz; pDvInfo->supports_YUV422_12bit = pvDvType1_1->supports_YUV422_12bit; pDvInfo->dm_version = pvDvType1_1->dm_version; pDvInfo->supports_global_dimming = pvDvType1_1->supports_global_dimming; pDvInfo->colorimetry = pvDvType1_1->colorimetry; pDvInfo->target_min_luminance = pvDvType1_1->target_min_luminance; pDvInfo->target_max_luminance = pvDvType1_1->target_max_luminance; pDvInfo->cc_green_x = NVT_DOLBY_CHROMATICITY_MSB_GX | pvDvType1_1->unique_Gx; pDvInfo->cc_green_y = NVT_DOLBY_CHROMATICITY_MSB_GY | pvDvType1_1->unique_Gy; pDvInfo->cc_blue_x = NVT_DOLBY_CHROMATICITY_MSB_BX | pvDvType1_1->unique_Bx; pDvInfo->cc_blue_y = NVT_DOLBY_CHROMATICITY_MSB_BY | pvDvType1_1->unique_By; pDvInfo->cc_red_x = NVT_DOLBY_CHROMATICITY_MSB_RX | pvDvType1_1->unique_Rx; pDvInfo->cc_red_y = NVT_DOLBY_CHROMATICITY_MSB_RY | (pvDvType1_1->unique_Ry_bit_0 | (pvDvType1_1->unique_Ry_bit_1 <<1) | (pvDvType1_1->unique_Ry_bit_2_to_4 << 2)); pDvInfo->supports_backlight_control = 0; pDvInfo->backlt_min_luma = 0; pDvInfo->interface_supported_by_sink = pvDvType1_1->interface_supported_by_sink; pDvInfo->supports_10b_12b_444 = 0; pDvInfo->cc_white_x = 0; pDvInfo->cc_white_y = 0; } else { return; } break; case 2: if (pExt861->vsvdb.vendor_data_size < sizeof(NVT_DV_STATIC_METADATA_TYPE2)) { return; } pDvType2 = (NVT_DV_STATIC_METADATA_TYPE2 *)(&pExt861->vsvdb.vendor_data); // copy the data pDvInfo->VSVDB_version = pDvType2->VSVDB_version; pDvInfo->supports_backlight_control = pDvType2->supports_backlight_control; pDvInfo->supports_YUV422_12bit = pDvType2->supports_YUV422_12bit; pDvInfo->dm_version = pDvType2->dm_version; pDvInfo->supports_global_dimming = pDvType2->supports_global_dimming; pDvInfo->target_min_luminance = pDvType2->target_min_luminance; pDvInfo->interface_supported_by_sink = pDvType2->interface_supported_by_sink; pDvInfo->parity = pDvType2->parity; pDvInfo->target_max_luminance = pDvType2->target_max_luminance; pDvInfo->cc_green_x = NVT_DOLBY_CHROMATICITY_MSB_GX | pDvType2->unique_Gx; pDvInfo->cc_green_y = NVT_DOLBY_CHROMATICITY_MSB_GY | pDvType2->unique_Gy; pDvInfo->cc_blue_x = NVT_DOLBY_CHROMATICITY_MSB_BX | pDvType2->unique_Bx; pDvInfo->cc_blue_y = NVT_DOLBY_CHROMATICITY_MSB_BY | pDvType2->unique_By; pDvInfo->cc_red_x = NVT_DOLBY_CHROMATICITY_MSB_RX | pDvType2->unique_Rx; pDvInfo->cc_red_y = NVT_DOLBY_CHROMATICITY_MSB_RY | pDvType2->unique_Ry; pDvInfo->supports_10b_12b_444 = pDvType2->supports_10b_12b_444_bit0 | (pDvType2->supports_10b_12b_444_bit1 << 1); pDvInfo->colorimetry = 0; pDvInfo->supports_2160p60hz = 0; pDvInfo->cc_white_x = 0; pDvInfo->cc_white_y = 0; break; default: break; } } // find both hdmi llc and hdmi forum vendor specific data block and return basic hdmi information CODE_SEGMENT(PAGE_DD_CODE) void parseCta861VsdbBlocks(NVT_EDID_CEA861_INFO *pExt861, void *pRawInfo, NVT_CTA861_ORIGIN flag ) { NvU32 i; NVT_EDID_INFO *pInfo = NULL; NVT_DISPLAYID_2_0_INFO *pDisplayID20 = NULL; NVT_HDMI_LLC_INFO *pHdmiLlc = NULL; NVT_HDMI_FORUM_INFO *pHfvs = NULL; NVDA_VSDB_PARSED_INFO *pNvVsdb = NULL; MSFT_VSDB_PARSED_INFO *pMsftVsdb = NULL; if (pExt861 == NULL || pRawInfo == NULL) { return; } if (flag == FROM_CTA861_EXTENSION || flag == FROM_DISPLAYID_13_DATA_BLOCK) { pInfo = (NVT_EDID_INFO *)pRawInfo; pHdmiLlc = &pInfo->hdmiLlcInfo; pHfvs = &pInfo->hdmiForumInfo; pNvVsdb = &pInfo->nvdaVsdbInfo; pMsftVsdb = &pInfo->msftVsdbInfo; } else if (flag == FROM_DISPLAYID_20_DATA_BLOCK) { pDisplayID20 = (NVT_DISPLAYID_2_0_INFO *)pRawInfo; pHdmiLlc = &pDisplayID20->vendor_specific.hdmiLlc; pHfvs = &pDisplayID20->vendor_specific.hfvs; pNvVsdb = &pDisplayID20->vendor_specific.nvVsdb; pMsftVsdb = &pDisplayID20->vendor_specific.msftVsdb; } else { return; } if (pHdmiLlc == NULL || pHfvs == NULL || pNvVsdb == NULL || pMsftVsdb == NULL || (pExt861->total_vsdb == 0)) { return; } for (i = 0; i < pExt861->total_vsdb; i++) { // Assumes each vsdb is unique for this CEA block, e.g., no two HDMI_IEEE_ID switch (pExt861->vsdb[i].ieee_id) { case NVT_CEA861_HDMI_IEEE_ID: // set any 3D timings and HDMI extended timing specified in the VSDB parseEdidHdmiLlcBasicInfo((VSDB_DATA *)(&pExt861->vsdb[i]), pHdmiLlc); pExt861->valid.H14B_VSDB = 1; break; case NVT_CEA861_HDMI_FORUM_IEEE_ID: parseEdidHdmiForumVSDB((VSDB_DATA *)(&pExt861->vsdb[i]), pHfvs); pExt861->valid.H20_HF_VSDB = 1; break; case NVT_CEA861_NVDA_IEEE_ID: parseEdidNvidiaVSDBBlock((VSDB_DATA *)(&pExt861->vsdb[i]), pNvVsdb); pExt861->valid.nvda_vsdb = 1; break; case NVT_CEA861_MSFT_IEEE_ID: parseEdidMsftVsdbBlock((VSDB_DATA *)(&pExt861->vsdb[i]), pMsftVsdb); pExt861->valid.msft_vsdb = 1; break; } } // H20_HF_VSDB shall be listed only if H14B_VSDB is also listed // H20_HF_VSDB should not specify > 600MHz nvt_assert(!pExt861->valid.H20_HF_VSDB || (pExt861->valid.H14B_VSDB && (pHfvs->max_TMDS_char_rate <= 0x78))); // Done with reading CEA VSDB blocks, sanitize them now if (pExt861->valid.SCDB) { pHdmiLlc->effective_tmds_clock = pExt861->hfscdb[1]; } else if (pExt861->valid.H14B_VSDB) { // HDMI 2.0 Spec - section 10.3.2 // The maximum Rate = Max_TMDS_Character_Rate * 5 MHz. // If the Sink does not support TMDS Character Rates > 340 Mcsc, then the Sink shall set this field to 0. // If the Sink supports TMDS Character Rates > 340 Mcsc, the Sink shall set Max_TMDS_Character_Rate appropriately and non - zero. // Pick updated TMDS clock rate pHdmiLlc->effective_tmds_clock = (pExt861->valid.H20_HF_VSDB) ? MAX(pHdmiLlc->max_tmds_clock, pHfvs->max_TMDS_char_rate) : MIN(pHdmiLlc->max_tmds_clock, 0x44); } } CODE_SEGMENT(PAGE_DD_CODE) void parseCta861HfEeodb(NVT_EDID_CEA861_INFO *pExt861, NvU32 *pTotalEdidExtensions) { // *pTotalEdidExtensions set by the edid extension flag should be >= 1 for HFEEODB to be valid. if (pTotalEdidExtensions == NULL || pExt861 == NULL || !pExt861->valid.HF_EEODB || *pTotalEdidExtensions == 0) { return; } // HDMI 2.1 AmendmentA1 specifies that if EEODB is present sources shall ignore the Extension flag. // This effectively overrides the extension count from extension flag. *pTotalEdidExtensions = pExt861->hfeeodb; } CODE_SEGMENT(PAGE_DD_CODE) void parseCta861HfScdb(NVT_EDID_CEA861_INFO *pExt861, void *pRawInfo, NVT_CTA861_ORIGIN flag) { NVT_EDID_INFO *pInfo = (NVT_EDID_INFO *)pRawInfo; VSDB_DATA vsdbData; if (pExt861 == NULL || pRawInfo == NULL) { return; } if (!pExt861->valid.SCDB || pExt861->valid.H20_HF_VSDB) { return; } NVMISC_MEMSET(&vsdbData, 0, sizeof(vsdbData)); NVMISC_MEMCPY(&vsdbData.vendor_data, pExt861->hfscdb, sizeof(vsdbData.vendor_data)); vsdbData.vendor_data_size = pExt861->hfscdbSize; parseEdidHdmiForumVSDB(&vsdbData, &pInfo->hdmiForumInfo); } CODE_SEGMENT(PAGE_DD_CODE) void getEdidHDM1_4bVsdbTiming(NVT_EDID_INFO *pInfo) { NvU32 i = 0, j = 0; for (i = 0; i < 2; ++i) { NVT_EDID_CEA861_INFO *pExt861 = (0 == i) ? &pInfo->ext861 : &pInfo->ext861_2; for (j = 0; j < pExt861->total_vsdb; ++j) { switch (pExt861->vsdb[j].ieee_id) { case NVT_CEA861_HDMI_IEEE_ID: { NvU32 count = 0; // set any 3D timings and HDMI extended timing specified in the VSDB parseEdidHDMILLCTiming(pInfo, (VSDB_DATA *)(&pExt861->vsdb[j]), &count, &(pInfo->Hdmi3Dsupport)); pInfo->HDMI3DSupported = 0 < count; break; } default: break; } } } } // get the full EDID 861 extension info CODE_SEGMENT(PAGE_DD_CODE) NVT_STATUS get861ExtInfo(NvU8 *p, NvU32 size, NVT_EDID_CEA861_INFO *p861info) { NvU32 dtd_offset; // sanity check if (p == NULL || size < sizeof(EDIDV1STRUC)) { return NVT_STATUS_ERR; } // make sure we have 861 extension if (p[0] != 0x2 || p[1] < NVT_CEA861_REV_ORIGINAL) { return NVT_STATUS_ERR; } // DTD offset sanity check if (p[2] >= 1 && p[2] <= 3) { return NVT_STATUS_ERR; } // don't do anything further if p861info is NULL if (p861info == NULL) { return NVT_STATUS_SUCCESS; } // init NVMISC_MEMSET(p861info, 0, sizeof(NVT_EDID_CEA861_INFO)); // get the revision number p861info->revision = p[1]; // no extra info for 861-original, returning from here if (p861info->revision == NVT_CEA861_REV_ORIGINAL) { return NVT_STATUS_SUCCESS; } p861info->basic_caps = p[3]; // no extra info for 861-A, returning from here if (p861info->revision == NVT_CEA861_REV_A) { return NVT_STATUS_SUCCESS; } dtd_offset = (NvU32)p[2]; if (dtd_offset == 0 || dtd_offset == 4) { return NVT_STATUS_SUCCESS; } // resolve all short descriptors in the reserved block // reserved block starts from offset 04 to dtd_offset-1 return parseCta861DataBlockInfo(&p[4], dtd_offset - 4, p861info); } // 1. get the 861 extension tags info // 2. or validation purpose if p861info == NULL CODE_SEGMENT(PAGE_DD_CODE) NVT_STATUS parseCta861DataBlockInfo(NvU8 *p, NvU32 size, NVT_EDID_CEA861_INFO *p861info) { NvU32 i, j; NvU32 video_index = 0; NvU32 audio_index = 0; NvU32 speaker_index = 0; NvU32 vendor_index = 0; NvU32 yuv420vdb_index = 0; NvU32 yuv420cmdb_index = 0; NvU8 svr_index = 0; NvU32 ieee_id = 0; NvU32 tag, ext_tag, payload; i= 0; while (i < size) { // get the descriptor's tag and payload size tag = NVT_CEA861_GET_SHORT_DESCRIPTOR_TAG(p[i]); payload = NVT_CEA861_GET_SHORT_DESCRIPTOR_SIZE(p[i]); /*don't allow data colleciton totally size larger than [127 - 5 (tag, revision, offset, describing native video format, checksum)]*/ if ((i + payload > size) || (i + payload > 122)) { return NVT_STATUS_ERR; } // move the pointer to the payload section or extended Tag Code i++; // NvTiming_EDIDValidationMask will use the different tag/payload value to make sure each of cta861 data block legal if (p861info == NULL) { switch(tag) { case NVT_CEA861_TAG_AUDIO: case NVT_CEA861_TAG_VIDEO: case NVT_CEA861_TAG_SPEAKER_ALLOC: case NVT_CEA861_TAG_VESA_DTC: case NVT_CEA861_TAG_RSVD: case NVT_CEA861_TAG_RSVD1: break; case NVT_CEA861_TAG_VENDOR: if (payload < 3) return NVT_STATUS_ERR; break; case NVT_CEA861_TAG_EXTENDED_FLAG: if (payload >= 1) { ext_tag = p[i]; if (ext_tag == NVT_CEA861_EXT_TAG_VIDEO_CAP && payload < 2) return NVT_STATUS_ERR; else if (ext_tag == NVT_CEA861_EXT_TAG_COLORIMETRY && payload < 3) return NVT_STATUS_ERR; else if (ext_tag == NVT_CEA861_EXT_TAG_VIDEO_FORMAT_PREFERENCE && payload < 2) return NVT_STATUS_ERR; else if (ext_tag == NVT_CEA861_EXT_TAG_YCBCR420_VIDEO && payload < 2) return NVT_STATUS_ERR; else if (ext_tag == NVT_CEA861_EXT_TAG_YCBCR420_CAP && payload < 1) return NVT_STATUS_ERR; else if (ext_tag == NVT_CEA861_EXT_TAG_HDR_STATIC_METADATA && payload < 3) return NVT_STATUS_ERR; else if (ext_tag == NVT_CEA861_EXT_TAG_VENDOR_SPECIFIC_VIDEO && payload < 4) return NVT_STATUS_ERR; else if (ext_tag == NVT_CTA861_EXT_TAG_SCDB && payload < 7) return NVT_STATUS_ERR; else if (ext_tag == NVT_CEA861_EXT_TAG_HF_EEODB && payload != 2) return NVT_STATUS_ERR; } break; default: break; } return NVT_STATUS_SUCCESS; } // loop through all descriptors if (tag == NVT_CEA861_TAG_VIDEO) { // short video descriptor for (j = 0; j < payload; j ++, i ++, video_index ++) { if (video_index < NVT_CEA861_VIDEO_MAX_DESCRIPTOR) { p861info->video[video_index] = p[i]; } else { break; } } p861info->total_svd = (NvU8)video_index; } else if (tag == NVT_CEA861_TAG_AUDIO) { // short audio descriptor for (j = 0; j < payload / 3; j ++, i += 3, audio_index ++) { if (audio_index < NVT_CEA861_AUDIO_MAX_DESCRIPTOR) { p861info->audio[audio_index].byte1 = p[i]; p861info->audio[audio_index].byte2 = p[i+1]; p861info->audio[audio_index].byte3 = p[i+2]; } else { break; } } p861info->total_sad = (NvU8)audio_index; } else if (tag == NVT_CEA861_TAG_SPEAKER_ALLOC) { // speaker allocation descriptor for (j = 0; j < payload / 3; j ++, i += 3, speaker_index ++) { if (speaker_index < NVT_CEA861_SPEAKER_MAX_DESCRIPTOR) { p861info->speaker[speaker_index].byte1 = p[i]; p861info->speaker[speaker_index].byte2 = p[i+1]; p861info->speaker[speaker_index].byte3 = p[i+2]; } else { break; } } p861info->total_ssd = (NvU8)speaker_index; } else if (tag == NVT_CEA861_TAG_VENDOR) { if (vendor_index < NVT_CEA861_VSDB_MAX_BLOCKS) { if (payload < 3) { // This malformed payload will cause a hang below. return NVT_STATUS_ERR; } p861info->vsdb[vendor_index].ieee_id = p[i]; //IEEE ID low byte p861info->vsdb[vendor_index].ieee_id |= (p[i+1]) << 8; //IEEE ID middle byte p861info->vsdb[vendor_index].ieee_id |= (p[i+2]) << 16; //IEEE ID high byte p861info->vsdb[vendor_index].vendor_data_size = payload - 3; // move the pointer to the payload i += 3; // get the other vendor specific data for (j = 0; j < payload - 3; j ++, i ++) { if (j < NVT_CEA861_VSDB_PAYLOAD_MAX_LENGTH) { p861info->vsdb[vendor_index].vendor_data[j] = p[i]; } } vendor_index++; } } else if (tag == NVT_CEA861_TAG_EXTENDED_FLAG) { if (payload >= 1) { ext_tag = p[i]; if (ext_tag == NVT_CEA861_EXT_TAG_VIDEO_CAP && payload >= 2) { p861info->video_capability = p[i + 1] & NVT_CEA861_VIDEO_CAPABILITY_MASK; p861info->valid.VCDB = 1; i += 2; } else if (ext_tag == NVT_CEA861_EXT_TAG_COLORIMETRY && payload >= 3) { p861info->colorimetry.byte1 = p[i + 1] & NVT_CEA861_COLORIMETRY_MASK; p861info->colorimetry.byte2 = p[i + 2] & NVT_CEA861_GAMUT_METADATA_MASK; p861info->valid.colorimetry = 1; i += 3; } else if (ext_tag == NVT_CEA861_EXT_TAG_VIDEO_FORMAT_PREFERENCE && payload >= 2) { // when present, indicates the order of preference for selected Video Formats listed as DTDs and/or SVDs throughout Block 0 and the CTA Extensions of the // order of SVD preferred modes shall take precedence over preferred modes defined elsewhere in the EDID/CEA861 blocks // exclude the extended tag i++; payload--; for (j = 0; (j < payload) && (svr_index < NVT_CEA861_VFPDB_MAX_DESCRIPTOR); j++, i++, svr_index++) { p861info->svr_vfpdb[svr_index] = p[i]; } p861info->total_vfpdb = svr_index; } else if (ext_tag == NVT_CEA861_EXT_TAG_YCBCR420_VIDEO && payload >= 2) { // when present, list SVDs that are only supported in YCbCr 4:2:0 // exclude the extended tag i++; payload--; for (j = 0; (j < payload) && (yuv420vdb_index < NVT_CEA861_Y420VDB_MAX_DESCRIPTOR); j++, i++, yuv420vdb_index++) { p861info->svd_y420vdb[yuv420vdb_index] = p[i]; } p861info->total_y420vdb = (NvU8)yuv420vdb_index; } else if (ext_tag == NVT_CEA861_EXT_TAG_YCBCR420_CAP && payload >= 1) { // when present, provides bitmap to video SVDs that also support YCbCr 4:2:0 in addition to RGB, YCbCr 4:4:4, and/or YCbCr 4: 2:0 // exclude the extended tag i++; payload--; for (j = 0; (j < payload) && (yuv420cmdb_index < NVT_CEA861_Y420CMDB_MAX_DESCRIPTOR); j++, i++, yuv420cmdb_index++) { p861info->map_y420cmdb[yuv420cmdb_index] = p[i]; } p861info->total_y420cmdb = (NvU8)yuv420cmdb_index; p861info->valid.y420cmdb = 1; // total_y420cmdb is not enough as this could be 0. See CEA861-F 7.5.11 } else if(ext_tag == NVT_CEA861_EXT_TAG_HDR_STATIC_METADATA && payload >= 3) { p861info->hdr_static_metadata.byte1 = p[i + 1] & NVT_CEA861_EOTF_MASK; // This byte has bits which identify which EOTF supported by the sink. p861info->hdr_static_metadata.byte2 = p[i + 2] & NVT_CEA861_STATIC_METADATA_DESCRIPTOR_MASK; // This byte has bits which identify which Static Metadata descriptors are supported by the sink. i += 3; if (payload > 3) { p861info->hdr_static_metadata.byte3 = p[i]; i++; } if (payload > 4) { p861info->hdr_static_metadata.byte4 = p[i]; i++; } if (payload > 5) { p861info->hdr_static_metadata.byte5 = p[i]; i++; } p861info->valid.hdr_static_metadata = 1; } else if(ext_tag == NVT_CEA861_EXT_TAG_VENDOR_SPECIFIC_VIDEO) { ieee_id = p[i + 1]; //IEEE ID low byte ieee_id |= (p[i + 2]) << 8; //IEEE ID middle byte ieee_id |= (p[i + 3]) << 16; //IEEE ID high byte if ((ieee_id == NVT_CEA861_DV_IEEE_ID) || (ieee_id == NVT_CEA861_HDR10PLUS_IEEE_ID)) { // exclude the extended tag i++; payload--; p861info->vsvdb.ieee_id = ieee_id; p861info->vsvdb.vendor_data_size = payload - 3; // move the pointer to the payload i += 3; // get the other vendor specific video data for (j = 0; j < payload - 3; j++, i++) { if (j < NVT_CEA861_VSVDB_PAYLOAD_MAX_LENGTH) { p861info->vsvdb.vendor_data[j] = p[i]; } } if (p861info->vsvdb.ieee_id == NVT_CEA861_DV_IEEE_ID) { p861info->valid.dv_static_metadata = 1; } else if (p861info->vsvdb.ieee_id == NVT_CEA861_HDR10PLUS_IEEE_ID) { p861info->valid.hdr10Plus = 1; } } else { // skip the unsupported extended block i += payload; } } else if(ext_tag == NVT_CTA861_EXT_TAG_SCDB && payload >= 7) // sizeof(HDMI Forum Sink Capability Data Block) ranges between 7 to 31 bytes { // As per HDMI2.1 A1 amendment Sink Capability Data Structure(SCDS) can alternatively be included in HDMI Forum Sink Capability Data Block(HF-SCDB), // instead of HF-VSDB, to indicate HDMI2.1 capability. // Sinks will expose HF-SCDB if they do not expose HF-VSDB. // move pointer to SCDS i += 3; // Copy SCDS over to p861info->vsdb[vendor_index]. Parsing will later be handled in parseEdidHdmiForumVSDB(). for (j = 0; (j < payload - 3) && (j < NVT_CTA861_EXT_SCDB_PAYLOAD_MAX_LENGTH); j ++, i ++) { p861info->hfscdb[j] = p[i]; } p861info->hfscdbSize = MIN(payload - 3, NVT_CTA861_EXT_SCDB_PAYLOAD_MAX_LENGTH); p861info->valid.SCDB = 1; } else if (ext_tag == NVT_CEA861_EXT_TAG_HF_EEODB && payload == 2) { // Skip over extended tag i++; payload--; p861info->hfeeodb = p[i]; p861info->valid.HF_EEODB = 1; i += payload; } else { // skip the unrecognized extended block i += payload; } } } else { // reserved block, just skip here i += payload; } } p861info->total_vsdb = (NvU8)vendor_index; return NVT_STATUS_SUCCESS; } // enum the EIA/CEA 861B predefined timing CODE_SEGMENT(PAGE_DD_CODE) NVT_STATUS NvTiming_EnumCEA861bTiming(NvU32 ceaFormat, NVT_TIMING *pT) { if (pT == NULL || ceaFormat == 0 || ceaFormat > MAX_CEA861B_FORMAT) { return NVT_STATUS_ERR; } ceaFormat = NVT_GET_CTA_8BIT_VIC(ceaFormat); if (ceaFormat ==0) return NVT_STATUS_ERR; *pT = EIA861B[ceaFormat - 1]; // calculate the pixel clock pT->pclk = RRx1kToPclk (pT); NVT_SET_CEA_FORMAT(pT->etc.status, ceaFormat); NVT_SNPRINTF((char *)pT->etc.name, sizeof(pT->etc.name), "CTA-861G:#%3d:%dx%dx%3d.%03dHz/%s", (int)ceaFormat, (int)pT->HVisible, (int)((pT->interlaced ? 2 : 1)*pT->VVisible), (int)pT->etc.rrx1k/1000, (int)pT->etc.rrx1k%1000, (pT->interlaced ? "I":"P")); pT->etc.name[sizeof(pT->etc.name) - 1] = '\0'; return NVT_STATUS_SUCCESS; } // Check whether the given timing is a CEA 861 timing. CODE_SEGMENT(PAGE_DD_CODE) NvU32 NvTiming_GetCEA861TimingIndex (NVT_TIMING *pT) { NvU32 i = 0, j = 0; NvU32 ceaIndex = 0; NvU32 aspect_x; NvU32 aspect_y; if (pT == NULL) { return ceaIndex; } if (NVT_GET_CEA_FORMAT(pT->etc.status) != 0) { // CEA format has been set, done return NVT_GET_CEA_FORMAT(pT->etc.status); } aspect_x = nvt_aspect_x(pT->etc.aspect); aspect_y = nvt_aspect_y(pT->etc.aspect); // loop through the pre-defined CEA 861 table // Skip VIC1 - Although IT 640x480 video timing has a CE id, it is not a CE timing. See 3.1 // "General Video Format Requirements" section in CEA-861-E spec for (i = 1; i < MAX_CEA861B_FORMAT; i++) { if (NvTiming_IsTimingRelaxedEqual(pT, &EIA861B[i])) { // The timing matches with a CEA 861 timing. Set CEA format to NVT_TIMING.etc.status. ceaIndex = NVT_GET_TIMING_STATUS_SEQ(EIA861B[i].etc.status); if (!aspect_x || !aspect_y) { return ceaIndex; } // for the dual-aspect ratio timings we should further check the aspect ratio matching(16:9 or 4:3) based on the integer rounding error for (j = 0; j < MAX_EIA861B_DUAL_ASPECT_VICS; j++) { if (ceaIndex == EIA861B_DUAL_ASPECT_VICS[j][0]) { NvU32 ceaIndex1 = EIA861B_DUAL_ASPECT_VICS[j][1]; NvU32 format1 = axb_div_c(aspect_x, nvt_aspect_y(EIA861B[ceaIndex - 1].etc.aspect), aspect_y); NvU32 format2 = axb_div_c(aspect_x, nvt_aspect_y(EIA861B[ceaIndex1 - 1].etc.aspect), aspect_y); NvU32 format_1_diff = abs_delta(format1, nvt_aspect_x(EIA861B[ceaIndex - 1].etc.aspect)); NvU32 format_2_diff = abs_delta(format2, nvt_aspect_x(EIA861B[ceaIndex1 - 1].etc.aspect)); if (format_2_diff < format_1_diff) { ceaIndex = ceaIndex1; } break; } else if (ceaIndex < EIA861B_DUAL_ASPECT_VICS[j][0]) // not a dual-dspect ratio timing { break; } } break; } } return ceaIndex; } // calculate 861B based timing CODE_SEGMENT(PAGE_DD_CODE) NVT_STATUS NvTiming_CalcCEA861bTiming(NvU32 width, NvU32 height, NvU32 rr, NvU32 flag, NvU32 pixelRepeatCount, NVT_TIMING *pT) { NvU32 i = 0; NvU16 pixelRepeatMask = 1 << (pixelRepeatCount - 1); nvt_assert(pixelRepeatCount > 0 && pixelRepeatCount <= 10); if (pT == NULL) { return NVT_STATUS_ERR; } // loop through the table for (i = 0; i < MAX_CEA861B_FORMAT; i ++) { if ((EIA861B[i].etc.rep & pixelRepeatMask) == 0) { continue; } if (width == (NvU32)NvTiming_MaxFrameWidth(EIA861B[i].HVisible, pixelRepeatMask) && height == frame_height(EIA861B[i])&& rr == EIA861B[i].etc.rr && (!!(flag & NVT_PVT_INTERLACED_MASK)) == (!!EIA861B[i].interlaced)) { *pT = EIA861B[i]; // calculate the pixel clock pT->pclk = RRx1kToPclk (pT); NVT_SET_CEA_FORMAT(pT->etc.status, NVT_GET_TIMING_STATUS_SEQ(pT->etc.status)); NVT_SNPRINTF((char *)pT->etc.name, sizeof(pT->etc.name), "CTA-861G:#%3d:%dx%dx%3d.%03dHz/%s", (int)NVT_GET_TIMING_STATUS_SEQ(pT->etc.status), (int)pT->HVisible, (int)((pT->interlaced ? 2 : 1)*pT->VVisible), (int)pT->etc.rrx1k/1000, (int)pT->etc.rrx1k%1000, (pT->interlaced ? "I":"P")); pT->etc.name[sizeof(pT->etc.name) - 1] = '\0'; return NVT_STATUS_SUCCESS; } } return NVT_STATUS_ERR; } // Assign fields in NVT_VIDEO_INFOFRAME_CTRL, using NVT_TIMING CODE_SEGMENT(PAGE_DD_CODE) NVT_STATUS NvTiming_ConstructVideoInfoframeCtrl(const NVT_TIMING *pTiming, NVT_VIDEO_INFOFRAME_CTRL *pCtrl) { // setup VIC code it is not specified if (pCtrl->video_format_id == NVT_INFOFRAME_CTRL_DONTCARE || pCtrl->video_format_id == 0 || pCtrl->video_format_id > NVT_CEA861_1920X1080P_29970HZ_16X9) { // setup video format ID pCtrl->video_format_id = (NvU8)NVT_GET_CEA_FORMAT(pTiming->etc.status); if (pCtrl->video_format_id < NVT_CEA861_640X480P_59940HZ_4X3 || pCtrl->video_format_id > NVT_CTA861_4096x2160p_119880HZ_256X135) { // Prior RFE 543088 if (pCtrl->video_format_id == 0 && NVT_GET_TIMING_STATUS_TYPE(pTiming->etc.status) == NVT_TYPE_EDID_861ST) { pCtrl->video_format_id = (NvU8)NVT_GET_TIMING_STATUS_SEQ(pTiming->etc.status); } if (pCtrl->video_format_id == 0 && pTiming->HVisible == 640 && pTiming->VVisible == 480 && pTiming->interlaced == 0 && pTiming->etc.rr == 60) { pCtrl->video_format_id = NVT_CEA861_640X480P_59940HZ_4X3; } } } // for HDMI_EXT timing, AVI VIC should be 0. if (NVT_GET_TIMING_STATUS_TYPE(pTiming->etc.status) == NVT_TYPE_HDMI_EXT) { pCtrl->video_format_id = 0; } // setup aspect ratio it is not specified if (pCtrl->pic_aspect_ratio == NVT_INFOFRAME_CTRL_DONTCARE || pCtrl->pic_aspect_ratio == NVT_VIDEO_INFOFRAME_BYTE2_M1M0_NO_DATA || pCtrl->pic_aspect_ratio > NVT_VIDEO_INFOFRAME_BYTE2_M1M0_FUTURE) { // extract the screen measurements from the DTD aspect ratio. // (we pack the height & width in a DWORD to form the aspect ratio) NvU32 x,y; x = (pTiming->etc.aspect & 0x0fff); y = ((pTiming->etc.aspect >> 16) & 0x0fff); if (axb_div_c(y,3,x) == 4) { pCtrl->pic_aspect_ratio = NVT_VIDEO_INFOFRAME_BYTE2_M1M0_4X3; } else if (axb_div_c(y,9,x) == 16) { pCtrl->pic_aspect_ratio = NVT_VIDEO_INFOFRAME_BYTE2_M1M0_16X9; } else if (pCtrl->video_format_id == NVT_CEA861_640X480P_59940HZ_4X3) { pCtrl->pic_aspect_ratio = NVT_VIDEO_INFOFRAME_BYTE2_M1M0_4X3; } else { // default to no data, to cover other non-cea modes pCtrl->pic_aspect_ratio = NVT_VIDEO_INFOFRAME_BYTE2_M1M0_NO_DATA; } } if (pCtrl->it_content == NVT_INFOFRAME_CTRL_DONTCARE) { // Initialize ITC flag to NVT_VIDEO_INFOFRAME_BYTE3_ITC_IT_CONTENT pCtrl->it_content = NVT_VIDEO_INFOFRAME_BYTE3_ITC_IT_CONTENT; pCtrl->it_content_type = NVT_VIDEO_INFOFRAME_BYTE5_CN1CN0_GRAPHICS; } if (pCtrl->pixel_repeat == NVT_INFOFRAME_CTRL_DONTCARE) { // Initialize pixel repetitions NvU32 pixelRepeat = pTiming->etc.rep; LOWESTBITIDX_32(pixelRepeat); pCtrl->pixel_repeat = (NvU8)pixelRepeat; } return NVT_STATUS_SUCCESS; } // construct AVI video infoframe based on the user control and the current context state CODE_SEGMENT(PAGE_DD_CODE) NVT_STATUS NvTiming_ConstructVideoInfoframe(NVT_EDID_INFO *pEdidInfo, NVT_VIDEO_INFOFRAME_CTRL *pCtrl, NVT_VIDEO_INFOFRAME *pContext, NVT_VIDEO_INFOFRAME *pInfoFrame) { // parameter check if (pEdidInfo == NULL || pInfoFrame == NULL) { return NVT_STATUS_ERR; } // infoframe is only supported on 861A and later if (pEdidInfo->ext861.revision < NVT_CEA861_REV_A) { return NVT_STATUS_ERR; } // if context state is provided, use it to initialize the infoframe buffer if (pContext != NULL) { *pInfoFrame = *pContext; } else { *pInfoFrame = DEFAULT_VIDEO_INFOFRAME; } // init the header pInfoFrame->type = NVT_INFOFRAME_TYPE_VIDEO; // TODO : This is just to check the version, we still need to change lots of structure // "NVT_VIDEO_INFOFRAME" / "VIDEO_INFOFRAME" / "DEFAULT_VIDEO_INFOFRAME" / "NVM_DISP_STATE" etc.. // to accept the new ACE0-3 bits supported in the future. Right now no any sink to support this. // // Based on the latest CTA-861-G-Errata.pdf file, we need to do following logic to get the correct CTA861 version // When Y2 = 0, the following algorithm shall be used for AVI InfoFrame version selection: // if (C=3 and EC=7) // Sources shall use AVI InfoFrame Version 4. // Else if (VIC>=128) // Sources shall use AVI InfoFrame Version 3. // Else // Sources shall use AVI InfoFrame Version 2. // End if // if (pCtrl) { if (nvt_get_bits(pInfoFrame->byte1, NVT_VIDEO_INFOFRAME_BYTE1_Y2Y1Y0_MASK, NVT_VIDEO_INFOFRAME_BYTE1_Y2Y1Y0_SHIFT) <= NVT_VIDEO_INFOFRAME_BYTE1_Y2Y1Y0_FUTURE) // this shall be as 0 always. { if ((nvt_get_bits(pInfoFrame->byte2, NVT_VIDEO_INFOFRAME_BYTE2_C1C0_MASK, NVT_VIDEO_INFOFRAME_BYTE2_C1C0_SHIFT) == NVT_VIDEO_INFOFRAME_BYTE2_C1C0_EXT_COLORIMETRY) && //EC2-0 is based on the 7.5.5 at CTA861-G which DCI-P3 bit defined or notat byte4 (nvt_get_bits(pInfoFrame->byte3, NVT_VIDEO_INFOFRAME_BYTE3_EC_MASK, NVT_VIDEO_INFOFRAME_BYTE3_EC_SHIFT) == NVT_VIDEO_INFOFRAME_BYTE3_EC_AdditionalColorExt)) { pInfoFrame->version = NVT_VIDEO_INFOFRAME_VERSION_4; // just put the logic to get the correct version 4, but it shall not be used at currently stage. } else { pInfoFrame->version = (((pCtrl->video_format_id & NVT_VIDEO_INFOFRAME_BYTE4_VIC7) == NVT_VIDEO_INFOFRAME_BYTE4_VIC7) ? NVT_VIDEO_INFOFRAME_VERSION_3 : ((pEdidInfo->ext861.revision >= NVT_CEA861_REV_B) ? NVT_VIDEO_INFOFRAME_VERSION_2 : NVT_VIDEO_INFOFRAME_VERSION_1)); } } } else { pInfoFrame->version = (pEdidInfo->ext861.revision >= NVT_CEA861_REV_B) ? NVT_VIDEO_INFOFRAME_VERSION_2 : NVT_VIDEO_INFOFRAME_VERSION_1; } pInfoFrame->length = sizeof(NVT_VIDEO_INFOFRAME) - sizeof(NVT_INFOFRAME_HEADER); if (pInfoFrame->version < NVT_VIDEO_INFOFRAME_VERSION_3) { nvt_nvu8_set_bits(pInfoFrame->byte1, 0, NVT_VIDEO_INFOFRAME_BYTE1_RESERVED_MASK, NVT_VIDEO_INFOFRAME_BYTE1_RESERVED_SHIFT); } if (pInfoFrame->version == NVT_VIDEO_INFOFRAME_VERSION_2) { nvt_nvu8_set_bits(pInfoFrame->byte4, 0, NVT_VIDEO_INFOFRAME_BYTE4_RESERVED_V2_MASK, NVT_VIDEO_INFOFRAME_BYTE4_RESERVED_V2_SHIFT); } else if (pInfoFrame->version == NVT_VIDEO_INFOFRAME_VERSION_1) { nvt_nvu8_set_bits(pInfoFrame->byte3, 0, NVT_VIDEO_INFOFRAME_BYTE3_RESERVED_V1_MASK, NVT_VIDEO_INFOFRAME_BYTE3_RESERVED_V1_SHIFT); nvt_nvu8_set_bits(pInfoFrame->byte4, 0, NVT_VIDEO_INFOFRAME_BYTE4_RESERVED_V1_MASK, NVT_VIDEO_INFOFRAME_BYTE4_RESERVED_V1_SHIFT); nvt_nvu8_set_bits(pInfoFrame->byte5, 0, NVT_VIDEO_INFOFRAME_BYTE5_RESERVED_V1_MASK, NVT_VIDEO_INFOFRAME_BYTE5_RESERVED_V1_SHIFT); } // construct the desired infoframe contents based on the control if (pCtrl) { // byte 1 if (pCtrl->color_space != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte1, pCtrl->color_space, NVT_VIDEO_INFOFRAME_BYTE1_Y2Y1Y0_MASK, NVT_VIDEO_INFOFRAME_BYTE1_Y2Y1Y0_SHIFT); } if (pCtrl->active_format_info_present != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte1, pCtrl->active_format_info_present, NVT_VIDEO_INFOFRAME_BYTE1_A0_MASK, NVT_VIDEO_INFOFRAME_BYTE1_A0_SHIFT); } if (pCtrl->bar_info != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte1, pCtrl->bar_info, NVT_VIDEO_INFOFRAME_BYTE1_B1B0_MASK, NVT_VIDEO_INFOFRAME_BYTE1_B1B0_SHIFT); } if (pCtrl->scan_info != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte1, pCtrl->scan_info, NVT_VIDEO_INFOFRAME_BYTE1_S1S0_MASK, NVT_VIDEO_INFOFRAME_BYTE1_S1S0_SHIFT); } // byte 2 if (pCtrl->colorimetry != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte2, pCtrl->colorimetry, NVT_VIDEO_INFOFRAME_BYTE2_C1C0_MASK, NVT_VIDEO_INFOFRAME_BYTE2_C1C0_SHIFT); } if (pCtrl->pic_aspect_ratio != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte2, pCtrl->pic_aspect_ratio, NVT_VIDEO_INFOFRAME_BYTE2_M1M0_MASK, NVT_VIDEO_INFOFRAME_BYTE2_M1M0_SHIFT); } if (pCtrl->active_format_aspect_ratio != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte2, pCtrl->active_format_aspect_ratio, NVT_VIDEO_INFOFRAME_BYTE2_R3R2R1R0_MASK, NVT_VIDEO_INFOFRAME_BYTE2_R3R2R1R0_SHIFT); } // byte 3 if (pCtrl->it_content != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte3, pCtrl->it_content, NVT_VIDEO_INFOFRAME_BYTE3_ITC_MASK, NVT_VIDEO_INFOFRAME_BYTE3_ITC_SHIFT); } if (pCtrl->extended_colorimetry != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte3, pCtrl->extended_colorimetry, NVT_VIDEO_INFOFRAME_BYTE3_EC_MASK, NVT_VIDEO_INFOFRAME_BYTE3_EC_SHIFT); } if (pCtrl->rgb_quantization_range != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte3, pCtrl->rgb_quantization_range, NVT_VIDEO_INFOFRAME_BYTE3_Q1Q0_MASK, NVT_VIDEO_INFOFRAME_BYTE3_Q1Q0_SHIFT); } if (pCtrl->nonuniform_scaling != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte3, pCtrl->nonuniform_scaling, NVT_VIDEO_INFOFRAME_BYTE3_SC_MASK, NVT_VIDEO_INFOFRAME_BYTE3_SC_SHIFT); } // byte 4 and byte 5 only supported on InfoFrame 2.0 if (pInfoFrame->version >= NVT_VIDEO_INFOFRAME_VERSION_2) { // byte 4 if (pCtrl->video_format_id != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte4, pCtrl->video_format_id, NVT_VIDEO_INFOFRAME_BYTE4_VIC_MASK, NVT_VIDEO_INFOFRAME_BYTE4_VIC_SHIFT); } // byte 5 if (pCtrl->pixel_repeat != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte5, pCtrl->pixel_repeat, NVT_VIDEO_INFOFRAME_BYTE5_PR_MASK, NVT_VIDEO_INFOFRAME_BYTE5_PR_SHIFT); } // byte5 if (pCtrl->it_content_type != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte5, pCtrl->it_content_type, NVT_VIDEO_INFOFRAME_BYTE5_CN1CN0_MASK, NVT_VIDEO_INFOFRAME_BYTE5_CN1CN0_SHIFT); } } // byte 6~13, bar info if (pCtrl->top_bar != 0xFFFF) { pInfoFrame->top_bar_low = (NvU8)(pCtrl->top_bar % 0x100); pInfoFrame->top_bar_high = (NvU8)(pCtrl->top_bar / 0x100); } if (pCtrl->bottom_bar != 0xFFFF) { pInfoFrame->bottom_bar_low = (NvU8)(pCtrl->bottom_bar % 0x100); pInfoFrame->bottom_bar_high = (NvU8)(pCtrl->bottom_bar / 0x100); } if (pCtrl->left_bar != 0xFFFF) { pInfoFrame->left_bar_low = (NvU8)(pCtrl->left_bar % 0x100); pInfoFrame->left_bar_high = (NvU8)(pCtrl->left_bar / 0x100); } if (pCtrl->right_bar != 0xFFFF) { pInfoFrame->right_bar_low = (NvU8)(pCtrl->right_bar % 0x100); pInfoFrame->right_bar_high = (NvU8)(pCtrl->right_bar / 0x100); } } return NVT_STATUS_SUCCESS; } // construct AVI audio infoframe based on the user control and the current context state CODE_SEGMENT(PAGE_DD_CODE) NVT_STATUS NvTiming_ConstructAudioInfoframe(NVT_AUDIO_INFOFRAME_CTRL *pUserCtrl, NVT_AUDIO_INFOFRAME *pContext, NVT_AUDIO_INFOFRAME *pInfoFrame) { NVT_AUDIO_INFOFRAME_CTRL ctrl; // parameter check if (pInfoFrame == NULL) { return NVT_STATUS_ERR; } // use the user provided control if possible if (pUserCtrl) { ctrl = *pUserCtrl; } else { // otherwise use the default control NVMISC_MEMSET(&ctrl, NVT_INFOFRAME_CTRL_DONTCARE, sizeof(ctrl)); } // if context state is provided, use it to initialize the infoframe buffer if (pContext != NULL) { *pInfoFrame = *pContext; } else { *pInfoFrame = DEFAULT_AUDIO_INFOFRAME; // if the context state is not provide, we should user EDID info to build a default ctrl //buildDefaultAudioInfoframeCtrl(pEdidInfo, &ctrl); } // init the header pInfoFrame->type = NVT_INFOFRAME_TYPE_AUDIO; pInfoFrame->version = NVT_VIDEO_INFOFRAME_VERSION_1; pInfoFrame->length = sizeof(NVT_AUDIO_INFOFRAME) - sizeof(NVT_INFOFRAME_HEADER); // init the reserved fields nvt_nvu8_set_bits(pInfoFrame->byte1, 0, NVT_AUDIO_INFOFRAME_BYTE1_RESERVED_MASK, NVT_AUDIO_INFOFRAME_BYTE1_RESERVED_SHIFT); nvt_nvu8_set_bits(pInfoFrame->byte2, 0, NVT_AUDIO_INFOFRAME_BYTE2_RESERVED_MASK, NVT_AUDIO_INFOFRAME_BYTE2_RESERVED_SHIFT); nvt_nvu8_set_bits(pInfoFrame->byte5, 0, NVT_AUDIO_INFOFRAME_BYTE5_RESERVED_MASK, NVT_AUDIO_INFOFRAME_BYTE5_RESERVED_SHIFT); pInfoFrame->rsvd_byte6 = 0; pInfoFrame->rsvd_byte7 = 0; pInfoFrame->rsvd_byte8 = 0; pInfoFrame->rsvd_byte9 = 0; pInfoFrame->rsvd_byte10 = 0; // byte 1 if (ctrl.channel_count != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte1, ctrl.channel_count, NVT_AUDIO_INFOFRAME_BYTE1_CC_MASK, NVT_AUDIO_INFOFRAME_BYTE1_CC_SHIFT); } if (ctrl.coding_type != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte1, ctrl.coding_type, NVT_AUDIO_INFOFRAME_BYTE1_CT_MASK, NVT_AUDIO_INFOFRAME_BYTE1_CT_SHIFT); } // byte 2 if (ctrl.sample_depth != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte2, ctrl.sample_depth, NVT_AUDIO_INFOFRAME_BYTE2_SS_MASK, NVT_AUDIO_INFOFRAME_BYTE2_SS_SHIFT); } if (ctrl.sample_rate != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte2, ctrl.sample_rate, NVT_AUDIO_INFOFRAME_BYTE2_SF_MASK, NVT_AUDIO_INFOFRAME_BYTE2_SF_SHIFT); } // byte 3 pInfoFrame->byte3 = 0; // byte 4 if (ctrl.speaker_placement != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte4, ctrl.speaker_placement, NVT_AUDIO_INFOFRAME_BYTE4_CA_MASK, NVT_AUDIO_INFOFRAME_BYTE4_CA_SHIFT); } // byte 5 if (ctrl.level_shift != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte5, ctrl.level_shift, NVT_AUDIO_INFOFRAME_BYTE5_LSV_MASK, NVT_AUDIO_INFOFRAME_BYTE5_LSV_SHIFT); } if (ctrl.down_mix_inhibit != NVT_INFOFRAME_CTRL_DONTCARE) { nvt_nvu8_set_bits(pInfoFrame->byte5, ctrl.down_mix_inhibit, NVT_AUDIO_INFOFRAME_BYTE5_DM_INH_MASK, NVT_AUDIO_INFOFRAME_BYTE5_DM_INH_SHIFT); } return NVT_STATUS_SUCCESS; } // Construct Vendor Specific Infoframe CODE_SEGMENT(PAGE_DD_CODE) NVT_STATUS NvTiming_ConstructVendorSpecificInfoframe(NVT_EDID_INFO *pEdidInfo, NVT_VENDOR_SPECIFIC_INFOFRAME_CTRL *pCtrl, NVT_VENDOR_SPECIFIC_INFOFRAME *pInfoFrame) { NVT_STATUS RetCode = NVT_STATUS_SUCCESS; NvU8 optIdx = 0; NvU8 HDMIFormat; // parameter check if (pEdidInfo == NULL || pInfoFrame == NULL) { return NVT_STATUS_INVALID_PARAMETER; } // infoframe is only supported on 861A and later if (pEdidInfo->ext861.revision < NVT_CEA861_REV_A) { return NVT_STATUS_ERR; } // initialize the infoframe buffer *pInfoFrame = DEFAULT_VENDOR_SPECIFIC_INFOFRAME; // init the header (mostly done in default Infoframe) pInfoFrame->Header.length = offsetof(NVT_VENDOR_SPECIFIC_INFOFRAME_PAYLOAD, optionalBytes); // construct the desired infoframe contents based on the control if (pCtrl) { // clear all static reserved fields nvt_nvu8_set_bits(pInfoFrame->Data.byte4, 0, NVT_HDMI_VS_BYTE4_RSVD_MASK, NVT_HDMI_VS_BYTE4_RSVD_SHIFT); // setup the parameters nvt_nvu8_set_bits(pInfoFrame->Data.byte4, pCtrl->HDMIFormat, NVT_HDMI_VS_BYTE4_HDMI_VID_FMT_MASK, NVT_HDMI_VS_BYTE4_HDMI_VID_FMT_SHIFT); // determine what the format is -- if disabled, force the format to NONE. if (pCtrl->Enable) { HDMIFormat = pCtrl->HDMIFormat; } else { HDMIFormat = NVT_HDMI_VS_BYTE4_HDMI_VID_FMT_NONE; } switch(HDMIFormat) { case NVT_HDMI_VS_BYTE4_HDMI_VID_FMT_NONE: { nvt_nvu8_set_bits(pInfoFrame->Data.byte5, 0, NVT_HDMI_VS_BYTENv_RSVD_MASK, NVT_HDMI_VS_BYTENv_RSVD_SHIFT); break; } case NVT_HDMI_VS_BYTE4_HDMI_VID_FMT_EXT: { // Note: extended resolution frames are not yet fully supported nvt_nvu8_set_bits(pInfoFrame->Data.byte5, pCtrl->HDMI_VIC, NVT_HDMI_VS_BYTE5_HDMI_VIC_MASK, NVT_HDMI_VS_BYTE5_HDMI_VIC_SHIFT); break; } case NVT_HDMI_VS_BYTE4_HDMI_VID_FMT_3D: { nvt_nvu8_set_bits(pInfoFrame->Data.byte5, 0, NVT_HDMI_VS_BYTE5_HDMI_RSVD_MASK, NVT_HDMI_VS_BYTE5_HDMI_RSVD_SHIFT); nvt_nvu8_set_bits(pInfoFrame->Data.byte5, pCtrl->ThreeDStruc, NVT_HDMI_VS_BYTE5_HDMI_3DS_MASK, NVT_HDMI_VS_BYTE5_HDMI_3DS_SHIFT); // side by side half requires additional format data in the infoframe. if (NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEHALF == pCtrl->ThreeDStruc) { nvt_nvu8_set_bits(pInfoFrame->Data.optionalBytes[optIdx], pCtrl->ThreeDDetail, NVT_HDMI_VS_BYTE_OPT1_HDMI_3DEX_MASK, NVT_HDMI_VS_BYTE_OPT1_HDMI_3DEX_SHIFT); optIdx++; } if (pCtrl->MetadataPresent) { nvt_nvu8_set_bits(pInfoFrame->Data.byte5, NVT_HDMI_VS_BYTE5_HDMI_META_PRESENT_PRES, NVT_HDMI_VS_BYTE5_3D_META_PRESENT_MASK, NVT_HDMI_VS_BYTE5_3D_META_PRESENT_SHIFT); switch(pCtrl->MetadataType) { case NVT_HDMI_VS_BYTE_OPT2_HDMI_METADATA_TYPE_PARALLAX: { if (sizeof(pCtrl->Metadata) >= NVT_HDMI_VS_BYTE_OPT2_HDMI_METADATA_LEN_PARALLAX && sizeof(pInfoFrame->Data.optionalBytes) - (optIdx + 1) >= NVT_HDMI_VS_BYTE_OPT2_HDMI_METADATA_LEN_PARALLAX) { nvt_nvu8_set_bits(pInfoFrame->Data.optionalBytes[optIdx], NVT_HDMI_VS_BYTE_OPT2_HDMI_METADATA_LEN_PARALLAX, NVT_HDMI_VS_BYTE_OPT2_HDMI_METADATA_LEN_MASK, NVT_HDMI_VS_BYTE_OPT2_HDMI_METADATA_LEN_SHIFT); nvt_nvu8_set_bits(pInfoFrame->Data.optionalBytes[optIdx], NVT_HDMI_VS_BYTE_OPT2_HDMI_METADATA_TYPE_PARALLAX, NVT_HDMI_VS_BYTE_OPT2_HDMI_METADATA_TYPE_MASK, NVT_HDMI_VS_BYTE_OPT2_HDMI_METADATA_TYPE_SHIFT); ++optIdx; NVMISC_MEMCPY(pCtrl->Metadata, &pInfoFrame->Data.optionalBytes[optIdx], NVT_HDMI_VS_BYTE_OPT2_HDMI_METADATA_LEN_PARALLAX); optIdx += NVT_HDMI_VS_BYTE_OPT2_HDMI_METADATA_LEN_PARALLAX; } else { // not enough data in the control struct or not enough room in the infoframe -- BOTH compile time issues!! // ignore metadata. nvt_nvu8_set_bits(pInfoFrame->Data.byte5, NVT_HDMI_VS_BYTE5_HDMI_META_PRESENT_NOTPRES, NVT_HDMI_VS_BYTE5_3D_META_PRESENT_MASK, NVT_HDMI_VS_BYTE5_3D_META_PRESENT_SHIFT); } break; } default: { // unrecognised metadata, recover the best we can. // note -- can not copy whatever is there because type implies length. nvt_nvu8_set_bits(pInfoFrame->Data.byte5, NVT_HDMI_VS_BYTE5_HDMI_META_PRESENT_NOTPRES, NVT_HDMI_VS_BYTE5_3D_META_PRESENT_MASK, NVT_HDMI_VS_BYTE5_3D_META_PRESENT_SHIFT); RetCode = NVT_STATUS_ERR; } } } else { nvt_nvu8_set_bits(pInfoFrame->Data.byte5, NVT_HDMI_VS_BYTE5_HDMI_META_PRESENT_NOTPRES, NVT_HDMI_VS_BYTE5_3D_META_PRESENT_MASK, NVT_HDMI_VS_BYTE5_3D_META_PRESENT_SHIFT); } break; } } // clear last byte of infoframe (reserved per spec). pInfoFrame->Header.length += optIdx + 1; for (; optIdx < sizeof(pInfoFrame->Data.optionalBytes); ++optIdx) { nvt_nvu8_set_bits(pInfoFrame->Data.optionalBytes[optIdx], NVT_HDMI_VS_BYTENv_RSVD, NVT_HDMI_VS_BYTENv_RSVD_MASK, NVT_HDMI_VS_BYTENv_RSVD_SHIFT); } } return RetCode; } // Construct Extended Metadata Packet Infoframe CODE_SEGMENT(PAGE_DD_CODE) NVT_STATUS NvTiming_ConstructExtendedMetadataPacketInfoframe( NVT_EXTENDED_METADATA_PACKET_INFOFRAME_CTRL *pCtrl, NVT_EXTENDED_METADATA_PACKET_INFOFRAME *pInfoFrame) { NVT_STATUS RetCode = NVT_STATUS_SUCCESS; if (!pCtrl || !pInfoFrame) { return NVT_STATUS_INVALID_PARAMETER; } // Initialize the infoframe NVMISC_MEMSET(pInfoFrame, 0, sizeof(*pInfoFrame)); // Construct an infoframe to enable or disable HDMI 2.1 VRR pInfoFrame->Header.type = NVT_INFOFRAME_TYPE_EXTENDED_METADATA_PACKET; pInfoFrame->Header.firstLast = NVT_EMP_HEADER_FIRST_LAST; pInfoFrame->Header.sequenceIndex = 0x00; nvt_nvu8_set_bits(pInfoFrame->Data.byte1, NVT_HDMI_EMP_BYTE1_VFR_ENABLE, NVT_HDMI_EMP_BYTE1_VFR_MASK, NVT_HDMI_EMP_BYTE1_VFR_SHIFT); nvt_nvu8_set_bits(pInfoFrame->Data.byte1, NVT_HDMI_EMP_BYTE1_NEW_ENABLE, NVT_HDMI_EMP_BYTE1_NEW_MASK, NVT_HDMI_EMP_BYTE1_NEW_SHIFT); if (!pCtrl->EnableVRR) { nvt_nvu8_set_bits(pInfoFrame->Data.byte1, NVT_HDMI_EMP_BYTE1_END_ENABLE, NVT_HDMI_EMP_BYTE1_END_MASK, NVT_HDMI_EMP_BYTE1_END_SHIFT); } nvt_nvu8_set_bits(pInfoFrame->Data.byte3, NVT_HDMI_EMP_BYTE3_ORGANIZATION_ID_SPEC_DEFINED, NVT_HDMI_EMP_BYTE3_ORGANIZATION_ID_MASK, NVT_HDMI_EMP_BYTE3_ORGANIZATION_ID_SHIFT); nvt_nvu8_set_bits(pInfoFrame->Data.byte5, 1, NVT_HDMI_EMP_BYTE5_DATA_SET_TAG_LSB_MASK, NVT_HDMI_EMP_BYTE5_DATA_SET_TAG_LSB_SHIFT); nvt_nvu8_set_bits(pInfoFrame->Data.byte7, (pCtrl->EnableVRR ? 4 : 0), NVT_HDMI_EMP_BYTE7_DATA_SET_LENGTH_LSB_MASK, NVT_HDMI_EMP_BYTE7_DATA_SET_LENGTH_LSB_SHIFT); if (pCtrl->EnableVRR) { nvt_nvu8_set_bits(pInfoFrame->Data.metadataBytes[0], NVT_HDMI_EMP_BYTE8_MD0_VRR_EN_ENABLE, NVT_HDMI_EMP_BYTE8_MD0_VRR_EN_MASK, NVT_HDMI_EMP_BYTE8_MD0_VRR_EN_SHIFT); } if (pCtrl->ITTiming) { nvt_nvu8_set_bits(pInfoFrame->Data.metadataBytes[1], pCtrl->BaseVFP, NVT_HDMI_EMP_BYTE8_MD1_BASE_VFRONT_MASK, NVT_HDMI_EMP_BYTE8_MD1_BASE_VFRONT_SHIFT); // In HDMI2.1, MD2 bit 2 is set when RB timing is used. // In HDMI2.1A, MD2 bit 2 is RSVD as 0 if (pCtrl->version == NVT_EXTENDED_METADATA_PACKET_INFOFRAME_VER_HDMI21) { nvt_nvu8_set_bits(pInfoFrame->Data.metadataBytes[2], pCtrl->ReducedBlanking, NVT_HDMI_EMP_BYTE8_MD2_RB_MASK, NVT_HDMI_EMP_BYTE8_MD2_RB_SHIFT); } // MSB for Base Refresh Rate nvt_nvu8_set_bits(pInfoFrame->Data.metadataBytes[2], pCtrl->BaseRefreshRate >> 8, NVT_HDMI_EMP_BYTE8_MD2_BASE_RR_MSB_MASK, NVT_HDMI_EMP_BYTE8_MD2_BASE_RR_MSB_SHIFT); // LSB for Base Refresh Rate nvt_nvu8_set_bits(pInfoFrame->Data.metadataBytes[3], pCtrl->BaseRefreshRate, NVT_HDMI_EMP_BYTE8_MD3_BASE_RR_LSB_MASK, NVT_HDMI_EMP_BYTE8_MD3_BASE_RR_LSB_SHIFT); } return RetCode; } // Enumerate Psf Timing CODE_SEGMENT(PAGE_DD_CODE) NVT_STATUS NvTiming_EnumNvPsfTiming(NvU32 nvPsfFormat, NVT_TIMING *pT) { if (pT == NULL || nvPsfFormat == 0 || nvPsfFormat > MAX_PSF_FORMAT) { return NVT_STATUS_ERR; } *pT = PSF_TIMING[nvPsfFormat - 1]; // calculate the pixel clock pT->pclk = RRx1kToPclk (pT); return NVT_STATUS_SUCCESS; } // Set ActiveSpace for HDMI 3D stereo timing CODE_SEGMENT(PAGE_DD_CODE) void SetActiveSpaceForHDMI3DStereo(const NVT_TIMING *pTiming, NVT_EXT_TIMING *pExtTiming) { // Note -- this assumes that the Timng is the 2D instance. NvU16 VBlank; // assume no active space to start. pExtTiming->HDMI3D.VActiveSpace[0] = 0; pExtTiming->HDMI3D.VActiveSpace[1] = 0; if (NVT_HDMI_VS_BYTE5_HDMI_3DS_FRAMEPACK == pExtTiming->HDMI3D.StereoStructureType) { VBlank = pTiming->VTotal - pTiming->VVisible; if (pTiming->interlaced) { //++++ This need to be revisited, not sure when active space 1 & 2 should be different. // (fortunately, we are not supporting any interlaced packed frame modes yet). pExtTiming->HDMI3D.VActiveSpace[0] = VBlank + 1; pExtTiming->HDMI3D.VActiveSpace[1] = VBlank - 1; } else { pExtTiming->HDMI3D.VActiveSpace[0] = VBlank; } } return; } // Generate HDMI stereo timing from 2D timing CODE_SEGMENT(PAGE_DD_CODE) void NvTiming_GetHDMIStereoTimingFrom2DTiming(const NVT_TIMING *pTiming, NvU8 StereoStructureType, NvU8 SideBySideHalfDetail, NVT_EXT_TIMING *pExtTiming) { NvU16 VBlank; NvU16 HBlank; if ((NULL == pTiming) || (NULL == pExtTiming) || (!isHdmi3DStereoType(StereoStructureType))) { return; } // init the extended timing NVMISC_MEMSET(pExtTiming, 0, sizeof(NVT_EXT_TIMING)); // copy the 2D timing to the 3D timing. pExtTiming->timing = *pTiming; // init the extension w/in the 3D timing pExtTiming->HDMI3D.StereoStructureType = StereoStructureType; pExtTiming->HDMI3D.SideBySideHalfDetail = SideBySideHalfDetail; switch(StereoStructureType) { case NVT_HDMI_VS_BYTE5_HDMI_3DS_FRAMEPACK: { // calculate VBlank VBlank = pTiming->VTotal - pTiming->VVisible; // Use the 2D timing to calculate the Active Space SetActiveSpaceForHDMI3DStereo(pTiming, pExtTiming); // Calculate the 3D VVisible size based on the 2D VVisible and the active space. if (pTiming->interlaced) { pExtTiming->timing.VVisible = ((pTiming->VVisible * 4) + (pExtTiming->HDMI3D.VActiveSpace[0]) * 2) + pExtTiming->HDMI3D.VActiveSpace[1]; } else { pExtTiming->timing.VVisible = (pTiming->VVisible * 2) + pExtTiming->HDMI3D.VActiveSpace[0]; } // Calculate the 3D VTotal from the 3D VVisible & the VBlank. pExtTiming->timing.VTotal = pExtTiming->timing.VVisible + VBlank; pExtTiming->timing.etc.status = NVT_SET_TIMING_STATUS_TYPE(pExtTiming->timing.etc.status, NVT_TYPE_HDMI_STEREO); break; } case NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEFULL: { // calculate HBlank before calculating new HVisible HBlank = pTiming->HTotal - pTiming->HVisible; pExtTiming->timing.HVisible = pTiming->HVisible * 2; pExtTiming->timing.HTotal = pExtTiming->timing.HVisible + HBlank; pExtTiming->timing.etc.status = NVT_SET_TIMING_STATUS_TYPE(pExtTiming->timing.etc.status, NVT_TYPE_HDMI_STEREO); break; } case NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEHALF: // valid formats with no timing changes. case NVT_HDMI_VS_BYTE5_HDMI_3DS_TOPBOTTOM: { break; } case NVT_HDMI_VS_BYTE5_HDMI_3DS_FIELD_ALT: // formats we are not supporting. case NVT_HDMI_VS_BYTE5_HDMI_3DS_LINE_ALT: case NVT_HDMI_VS_BYTE5_HDMI_3DS_LDEPTH: case NVT_HDMI_VS_BYTE5_HDMI_3DS_LDEPTHGFX: { break; } } // calculate the pixel clock pExtTiming->timing.pclk = RRx1kToPclk (&(pExtTiming->timing)); return; } // Add mode to 3D stereo support map CODE_SEGMENT(PAGE_DD_CODE) void AddModeToSupportMap(HDMI3DSUPPORTMAP * pMap, NvU8 Vic, NvU8 StereoStructureType, NvU8 SideBySideHalfDetail) { NvU32 i; if (0 < Vic) { // first check if the vic is already listed. for (i = 0; i < pMap->total; ++i) { if (pMap->map[i].Vic == Vic) { break; } } if (i == pMap->total) { // vic is not in the map. // add it. // note that we can't add the VIC to one of the 1st 16 entries. // 1st 16 entries in the map are reserved for the vics from the EDID. // if we add this VIC to the 1st 16, & there are any optional modes listed, // the optional mode(s) will be improperly applied to this VIC as well i = MAX(MAX_EDID_ADDRESSABLE_3D_VICS, pMap->total); if (i < MAX_3D_VICS_SUPPORTED) { pMap->map[i].Vic = Vic; pMap->total = i + 1; } } nvt_assert(pMap->total <= MAX_3D_VICS_SUPPORTED); if (i < pMap->total) { pMap->map[i].StereoStructureMask = pMap->map[i].StereoStructureMask | NVT_HDMI_3D_SUPPORTED_STRUCT_MASK(StereoStructureType); if (NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEHALF == StereoStructureType) { pMap->map[i].SideBySideHalfDetail = SideBySideHalfDetail; } } } } CODE_SEGMENT(PAGE_DD_CODE) void parseEdidHdmiLlcBasicInfo(VSDB_DATA *pVsdb, NVT_HDMI_LLC_INFO *pHdmiLlc) { NVT_HDMI_LLC_VSDB_PAYLOAD *p; if (pVsdb == NULL || pHdmiLlc == NULL) { return; } p = (NVT_HDMI_LLC_VSDB_PAYLOAD *)(&pVsdb->vendor_data); // Minimum vendor_data_size is 2 pHdmiLlc->addrA = p->A; pHdmiLlc->addrB = p->B; pHdmiLlc->addrC = p->C; pHdmiLlc->addrD = p->D; // If more data is provided, we read it as well each field at a time up to video latency if (pVsdb->vendor_data_size >= 3) { pHdmiLlc->supports_AI = p->Supports_AI; pHdmiLlc->dc_48_bit = p->DC_48bit; pHdmiLlc->dc_36_bit = p->DC_36bit; pHdmiLlc->dc_30_bit = p->DC_30bit; pHdmiLlc->dc_y444 = p->DC_Y444; pHdmiLlc->dual_dvi = p->DVI_Dual; if (pVsdb->vendor_data_size >= 4) { pHdmiLlc->max_tmds_clock = p->Max_TMDS_Clock; if (pVsdb->vendor_data_size >= 5) { pHdmiLlc->latency_field_present = p->Latency_Fields_Present; pHdmiLlc->i_latency_field_present = p->I_Latency_Fields_Present; pHdmiLlc->hdmi_video_present = p->HDMI_Video_present; pHdmiLlc->cnc3 = p->CNC3; pHdmiLlc->cnc2 = p->CNC2; pHdmiLlc->cnc1 = p->CNC1; pHdmiLlc->cnc0 = p->CNC0; } } } } // get HDMI 1.4 specific timing (3D stereo timings and extended mode timings) CODE_SEGMENT(PAGE_DD_CODE) void parseEdidHDMILLCTiming(NVT_EDID_INFO *pInfo, VSDB_DATA *pVsdb, NvU32 *pMapSz, HDMI3DSUPPORTMAP * pM) { NVT_HDMI_LLC_VSDB_PAYLOAD *pHdmiLLC; NVT_HDMI_VIDEO *pHDMIVideo; NvU32 DataCnt = 0; NvU32 DataSz; NvU16 i, j, k; NvU16 Supports50Hz; NvU16 Supports60Hz; NvU32 vendorDataSize; if ((NULL == pInfo) || (NULL == pVsdb) || (NULL == pM)) { return; } // init the support map NVMISC_MEMSET(pM, 0, sizeof(HDMI3DSUPPORTMAP)); Supports50Hz = 0; Supports60Hz = 0; nvt_assert(pInfo->total_timings <= COUNT(pInfo->timing)); for (i = 0; i < pInfo->total_timings; ++i) { if (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == NVT_TYPE_EDID_861ST) { if (MAX_EDID_ADDRESSABLE_3D_VICS > pM->total) { // fill in the VICs from the EDID (up to the 1st 16). These are used for applying any 3D optional modes listed in the LLC // -- the optional modes are addressed based on their relative location within the EDID. pM->map[pM->total].Vic = (NvU8) NVT_GET_TIMING_STATUS_SEQ(pInfo->timing[i].etc.status); ++pM->total; } // since we are spinning through the timing array anyway, // check to see which refresh rates are supported. if (50 == pInfo->timing[i].etc.rr) { Supports50Hz = 1; } else if (60 == pInfo->timing[i].etc.rr) { Supports60Hz = 1; } } } if (0 == pM->total) { if (NULL != pMapSz) { *pMapSz = 0; } } vendorDataSize = pVsdb->vendor_data_size; if ((NVT_CEA861_HDMI_IEEE_ID == pVsdb->ieee_id) && (offsetof(NVT_HDMI_LLC_VSDB_PAYLOAD, Data) < vendorDataSize)) { pHdmiLLC = (NVT_HDMI_LLC_VSDB_PAYLOAD *)(&pVsdb->vendor_data); DataSz = (NvU32) MIN(vendorDataSize - offsetof(NVT_HDMI_LLC_VSDB_PAYLOAD, Data), sizeof(pHdmiLLC->Data)); if (5 <= vendorDataSize) { if (pHdmiLLC->Latency_Fields_Present) { DataCnt += (NvU32) sizeof(NVT_CEA861_LATENCY); if (pHdmiLLC->I_Latency_Fields_Present) { DataCnt += (NvU32) sizeof(NVT_CEA861_LATENCY); } } if ((pHdmiLLC->HDMI_Video_present) && (DataSz > DataCnt) && (DataSz - DataCnt >= sizeof(NVT_HDMI_VIDEO))) { pHDMIVideo = (NVT_HDMI_VIDEO *) &pHdmiLLC->Data[DataCnt]; DataCnt += (NvU32) sizeof(NVT_HDMI_VIDEO); // If 3D is present, then add the basic 3D modes 1st. if (pHDMIVideo->ThreeD_Present) { if ((0 != Supports50Hz) || (0 != Supports60Hz)) { // 50 and / or 60 Hz is supported, add 1920 x 1080 @ 24Hz 3D modes. AddModeToSupportMap(pM, 32, NVT_HDMI_VS_BYTE5_HDMI_3DS_FRAMEPACK, 0); // 1920 x 1080p @ 24 Hz AddModeToSupportMap(pM, 32, NVT_HDMI_VS_BYTE5_HDMI_3DS_TOPBOTTOM, 0); // 1920 x 1080p @ 24 Hz if (0 != Supports50Hz) { // add the mandatory modes for 50 Hz AddModeToSupportMap(pM, 19, NVT_HDMI_VS_BYTE5_HDMI_3DS_FRAMEPACK, 0); // 1280 x 720p @ 50 Hz AddModeToSupportMap(pM, 19, NVT_HDMI_VS_BYTE5_HDMI_3DS_TOPBOTTOM, 0); // 1280 x 720p @ 50 Hz // 1920 x 1080i @ 50 Hz AddModeToSupportMap(pM, 20, NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEHALF, NVT_HDMI_VS_BYTE_OPT1_HDMI_3DEX_SSH); } if (0 != Supports60Hz) { // add the mandatory modes for 60 Hz AddModeToSupportMap(pM, 4, NVT_HDMI_VS_BYTE5_HDMI_3DS_FRAMEPACK, 0); // 1280 x 720p @ 60 Hz AddModeToSupportMap(pM, 4, NVT_HDMI_VS_BYTE5_HDMI_3DS_TOPBOTTOM, 0); // 1280 x 720p @ 60 Hz // 1920 x 1080i @ 60 Hz AddModeToSupportMap(pM, 5, NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEHALF, NVT_HDMI_VS_BYTE_OPT1_HDMI_3DEX_SSH); } } } if ((DataSz > DataCnt) && (DataSz - DataCnt >= pHDMIVideo->HDMI_VIC_Len)) { // handle HDMI VIC entries to add HDMI 1.4a 4kx2k extended modes NVT_HDMI_VIC_LIST * pVicList = (NVT_HDMI_VIC_LIST *) &pHdmiLLC->Data[DataCnt]; for ( k = 0; k < pHDMIVideo->HDMI_VIC_Len; ++k) { NVT_TIMING newTiming; // extended mode VIC code from 1 - 4. if ((0 < pVicList->HDMI_VIC[k]) && (pVicList->HDMI_VIC[k] <= MAX_HDMI_EXT_4Kx2K_FORMAT)) { NVMISC_MEMCPY(&newTiming, &HDMI_EXT_4Kx2K_TIMING[pVicList->HDMI_VIC[k] - 1], sizeof(newTiming)); // Fill in the pixel clock newTiming.pclk = RRx1kToPclk(&newTiming); if (!assignNextAvailableTiming(pInfo, &newTiming)) { break; } } } DataCnt += pHDMIVideo->HDMI_VIC_Len; } // the following code implements parsing the HDMI 3D additional modes (all modes bitmap & additional vic modes) // Kepler and above support 3D secondary modes if ((pHDMIVideo->ThreeD_Present) && ((1 == pHDMIVideo->ThreeD_Multi_Present) || (2 == pHDMIVideo->ThreeD_Multi_Present)) && (0 < pHDMIVideo->HDMI_3D_Len) && (DataSz > (DataCnt + 1)) && //make sure pHdmiLLC->Data[DataCnt + 1] is valid (DataSz - DataCnt >= pHDMIVideo->HDMI_3D_Len)) { NvU16 AllVicStructMask; NvU16 AllVicIdxMask; NvU8 AllVicDetail; // determine which modes to apply to all VICs. AllVicStructMask = (pHdmiLLC->Data[DataCnt] << 8) | pHdmiLLC->Data[DataCnt + 1]; AllVicStructMask = AllVicStructMask & NVT_ALL_HDMI_3D_STRUCT_SUPPORTED_MASK; DataCnt += 2; if ((2 == pHDMIVideo->ThreeD_Multi_Present) && (DataSz > (DataCnt+1))) //make sure pHdmiLLC->Data[DataCnt + 1] is valid { AllVicIdxMask = pHdmiLLC->Data[DataCnt] << 8 | pHdmiLLC->Data[DataCnt + 1]; DataCnt += 2; } else { AllVicIdxMask = 0xffff; } // determine what the detail should be. AllVicDetail = 0 != (AllVicStructMask & NVT_HDMI_3D_SUPPORTED_SIDEBYSIDEHALF_MASK) ? NVT_HDMI_VS_BYTE_OPT1_HDMI_3DEX_SSH : 0; // add the modes to the Support map for all the listed VICs. for (k = 0; k < MIN(MAX_EDID_ADDRESSABLE_3D_VICS, pM->total); ++k) { if ((0 != (AllVicIdxMask & (1 << k))) && (0 != pM->map[k].Vic)) { pM->map[k].StereoStructureMask = pM->map[k].StereoStructureMask | AllVicStructMask; pM->map[k].SideBySideHalfDetail = AllVicDetail; } } } // handle any additional per vic modes listed in the EDID while (DataSz > DataCnt) { // get a pointer to the entry. NVT_3D_MULTI_LIST * pMultiListEntry = (NVT_3D_MULTI_LIST *) &pHdmiLLC->Data[DataCnt]; // apply the specified structure to the Support Map pM->map[pMultiListEntry->TwoD_VIC_order].StereoStructureMask = pM->map[pMultiListEntry->TwoD_VIC_order].StereoStructureMask | NVT_HDMI_3D_SUPPORTED_STRUCT_MASK(pMultiListEntry->ThreeD_Structure); // increment the Data count by 2 if this is side by side half, // or 1 if it is any other structure. if (NVT_HDMI_VS_BYTE5_HDMI_3DS_SIDEBYSIDEHALF <= pMultiListEntry->ThreeD_Structure) { pM->map[pMultiListEntry->TwoD_VIC_order].SideBySideHalfDetail = pMultiListEntry->ThreeD_Detail; DataCnt += 2; } else { pM->map[pMultiListEntry->TwoD_VIC_order].SideBySideHalfDetail = 0; DataCnt += 1; } } } } } // compress out entries where there is no 3D support. for (i = 0, j = 0; i < pM->total; ++i) { if (0 != pM->map[i].StereoStructureMask) { pM->map[j] = pM->map[i]; ++j; } } pM->total = j; if (NULL != pMapSz) { *pMapSz = pM->total; } } // get HDMI 1.4 3D mandatory stereo format datail base on the input vic. // If the vic is not in the mandatory format list, return error. CODE_SEGMENT(PAGE_DD_CODE) NVT_STATUS NvTiming_GetHDMIStereoMandatoryFormatDetail(const NvU8 vic, NvU16 *pStereoStructureMask, NvU8 *pSideBySideHalfDetail) { NvU32 i; if ((vic < 1) || (vic > MAX_CEA861B_FORMAT)) { return NVT_STATUS_ERR; } for (i = 0; i < MAX_HDMI_MANDATORY_3D_FORMAT; i++) { if (vic == HDMI_MANDATORY_3D_FORMATS[i].Vic) { if (pStereoStructureMask != NULL) { *pStereoStructureMask = HDMI_MANDATORY_3D_FORMATS[i].StereoStructureMask; } if (pSideBySideHalfDetail != NULL) { *pSideBySideHalfDetail = HDMI_MANDATORY_3D_FORMATS[i].SideBySideHalfDetail; } return NVT_STATUS_SUCCESS; } } return NVT_STATUS_ERR; } // return the aspect ratio of a given CEA/EIA 861 timing CODE_SEGMENT(PAGE_DD_CODE) NvU32 getCEA861TimingAspectRatio(NvU32 vic) { return (vic > 0 && vic < MAX_CEA861B_FORMAT + 1) ? EIA861B[vic-1].etc.aspect : 0; } // expose the HDMI extended video timing defined by the HDMI LLC VSDB CODE_SEGMENT(PAGE_DD_CODE) NVT_STATUS NvTiming_EnumHdmiVsdbExtendedTiming(NvU32 hdmi_vic, NVT_TIMING *pT) { if (hdmi_vic > MAX_HDMI_EXT_4Kx2K_FORMAT || hdmi_vic == 0 || pT == NULL) { return NVT_STATUS_ERR; } *pT = HDMI_EXT_4Kx2K_TIMING[hdmi_vic - 1]; pT->pclk = RRx1kToPclk(pT); return NVT_STATUS_SUCCESS; } CODE_SEGMENT(PAGE_DD_CODE) void parseEdidNvidiaVSDBBlock(VSDB_DATA *pVsdb, NVDA_VSDB_PARSED_INFO *vsdbInfo) { NVT_NVDA_VSDB_PAYLOAD *pNvda; if ((pVsdb == NULL) || (vsdbInfo == NULL)) { return; } if ((NVT_CEA861_NVDA_IEEE_ID == pVsdb->ieee_id) && (pVsdb->vendor_data_size >= sizeof(NVT_NVDA_VSDB_PAYLOAD))) { pNvda = (NVT_NVDA_VSDB_PAYLOAD *)(&pVsdb->vendor_data); // only version 0x1 is supported if (pNvda->opcode == 0x1) { vsdbInfo->vsdbVersion = pNvda->opcode; } switch (vsdbInfo->vsdbVersion) { case 1: vsdbInfo->valid = NV_TRUE; vsdbInfo->vrrData.v1.supportsVrr = NV_TRUE; vsdbInfo->vrrData.v1.minRefreshRate = pNvda->vrrMinRefreshRate; break; default: break; } } } CODE_SEGMENT(PAGE_DD_CODE) void parseEdidMsftVsdbBlock(VSDB_DATA *pVsdb, MSFT_VSDB_PARSED_INFO *pVsdbInfo) { if ((pVsdb == NULL) || (pVsdbInfo == NULL)) { return; } NVMISC_MEMSET(pVsdbInfo, 0, sizeof(MSFT_VSDB_PARSED_INFO)); if ((NVT_CEA861_MSFT_IEEE_ID == pVsdb->ieee_id) && (pVsdb->vendor_data_size >= sizeof(NVT_MSFT_VSDB_PAYLOAD))) { NvU32 i = 0; NVT_MSFT_VSDB_PAYLOAD *pMsftVsdbPayload = (NVT_MSFT_VSDB_PAYLOAD *)(&pVsdb->vendor_data); pVsdbInfo->version = pMsftVsdbPayload->version; if (pVsdbInfo->version >= 1) { for (i = 0; i < MSFT_VSDB_CONTAINER_ID_SIZE; i++) { pVsdbInfo->containerId[i] = pMsftVsdbPayload->containerId[i]; } pVsdbInfo->desktopUsage = pMsftVsdbPayload->desktopUsage; pVsdbInfo->thirdPartyUsage = pMsftVsdbPayload->thirdPartyUsage; pVsdbInfo->valid = NV_TRUE; } // Version 3 is the latest version of MSFT VSDB at the time of writing this code // Any update from newer version will be ignored and be parsed as Version 3, till // we have an explicit handling for newer version here. if (pVsdbInfo->version >= 3) { // Primary Use case is valid from Version 3 and is ignored on previous versions. pVsdbInfo->primaryUseCase = pMsftVsdbPayload->primaryUseCase; } } } CODE_SEGMENT(PAGE_DD_CODE) void parseEdidHdmiForumVSDB(VSDB_DATA *pVsdb, NVT_HDMI_FORUM_INFO *pHdmiInfo) { NVT_HDMI_FORUM_VSDB_PAYLOAD *pHdmiForum; NvU32 remainingSize; if ((pVsdb == NULL) || pHdmiInfo == NULL) { return; } pHdmiForum = (NVT_HDMI_FORUM_VSDB_PAYLOAD *)(&pVsdb->vendor_data); switch(pHdmiForum->Version) { case 1: // From HDMI spec the payload data size is from 7 to 31 // In parseCta861DataBlockInfo(), the payload size recorded in pHdmiForum is // subtracted by 3. Thus the expected range here is 4 - 28. // Assert if the the vendor_data_size < 4. nvt_assert(pVsdb->vendor_data_size >= 4); remainingSize = pVsdb->vendor_data_size; // second byte pHdmiInfo->max_TMDS_char_rate = pHdmiForum->Max_TMDS_Character_Rate; // third byte pHdmiInfo->threeD_Osd_Disparity = pHdmiForum->ThreeD_Osd_Disparity; pHdmiInfo->dual_view = pHdmiForum->Dual_View; pHdmiInfo->independent_View = pHdmiForum->Independent_View; pHdmiInfo->lte_340Mcsc_scramble = pHdmiForum->Lte_340mcsc_Scramble; pHdmiInfo->ccbpci = pHdmiForum->CCBPCI; pHdmiInfo->cable_status = pHdmiForum->CABLE_STATUS; pHdmiInfo->rr_capable = pHdmiForum->RR_Capable; pHdmiInfo->scdc_present = pHdmiForum->SCDC_Present; // fourth byte pHdmiInfo->dc_30bit_420 = pHdmiForum->DC_30bit_420; pHdmiInfo->dc_36bit_420 = pHdmiForum->DC_36bit_420; pHdmiInfo->dc_48bit_420 = pHdmiForum->DC_48bit_420; pHdmiInfo->uhd_vic = pHdmiForum->UHD_VIC; pHdmiInfo->max_FRL_Rate = pHdmiForum->Max_FRL_Rate; remainingSize -= 4; // fifth byte if (!remainingSize--) { break; } pHdmiInfo->fapa_start_location = pHdmiForum->FAPA_start_location; pHdmiInfo->allm = pHdmiForum->ALLM; pHdmiInfo->fva = pHdmiForum->FVA; pHdmiInfo->cnmvrr = pHdmiForum->CNMVRR; pHdmiInfo->cinemaVrr = pHdmiForum->CinemaVRR; pHdmiInfo->m_delta = pHdmiForum->M_delta; pHdmiInfo->fapa_end_extended = pHdmiForum->FAPA_End_Extended; // sixth byte if (!remainingSize--) { break; } pHdmiInfo->vrr_min = pHdmiForum->VRR_min; pHdmiInfo->vrr_max = ((NvU16)pHdmiForum->VRR_max_high) << 8; // seventh byte if (!remainingSize--) { break; } pHdmiInfo->vrr_max |= (pHdmiForum->VRR_max_low); // eighth byte if (!remainingSize--) { break; } pHdmiInfo->dsc_10bpc = pHdmiForum->DSC_10bpc; pHdmiInfo->dsc_12bpc = pHdmiForum->DSC_12bpc; pHdmiInfo->dsc_16bpc = pHdmiForum->DSC_16bpc; pHdmiInfo->dsc_All_bpp = pHdmiForum->DSC_All_bpp; pHdmiInfo->dsc_Native_420 = pHdmiForum->DSC_Native_420; pHdmiInfo->dsc_1p2 = pHdmiForum->DSC_1p2; // ninth byte if (!remainingSize--) { break; } pHdmiInfo->dsc_MaxSlices = 0; pHdmiInfo->dsc_MaxPclkPerSliceMHz = 0; switch(pHdmiForum->DSC_MaxSlices) { case 7: pHdmiInfo->dsc_MaxSlices = 16; pHdmiInfo->dsc_MaxPclkPerSliceMHz = 400; break; case 6: pHdmiInfo->dsc_MaxSlices = 12; pHdmiInfo->dsc_MaxPclkPerSliceMHz = 400; break; case 5: pHdmiInfo->dsc_MaxSlices = 8; pHdmiInfo->dsc_MaxPclkPerSliceMHz = 400; break; case 4: pHdmiInfo->dsc_MaxSlices = 8; pHdmiInfo->dsc_MaxPclkPerSliceMHz = 340; break; case 3: pHdmiInfo->dsc_MaxSlices = 4; pHdmiInfo->dsc_MaxPclkPerSliceMHz = 340; break; case 2: pHdmiInfo->dsc_MaxSlices = 2; pHdmiInfo->dsc_MaxPclkPerSliceMHz = 340; break; case 1: pHdmiInfo->dsc_MaxSlices = 1; pHdmiInfo->dsc_MaxPclkPerSliceMHz = 340; break; default: break; } pHdmiInfo->dsc_Max_FRL_Rate = pHdmiForum->DSC_Max_FRL_Rate; // tenth byte if (!remainingSize--) { break; } // Per spec, number of bytes has to be computed as 1024 x (1 + DSC_TotalChunkKBytes). // For driver parser purposes, add 1 here so that the field means max num of KBytes in a link of chunks pHdmiInfo->dsc_totalChunkKBytes = (pHdmiForum->DSC_totalChunkKBytes == 0) ? 0 : pHdmiForum->DSC_totalChunkKBytes + 1; break; default: break; } } CODE_SEGMENT(PAGE_DD_CODE) void parseCea861Hdr10PlusDataBlock(NVT_EDID_CEA861_INFO *pExt861, void *pRawInfo, NVT_CTA861_ORIGIN flag) { NVT_EDID_INFO *pInfo = NULL; NVT_DISPLAYID_2_0_INFO *pDisplayID20 = NULL; NVT_HDR10PLUS_INFO *pHdr10PlusInfo = NULL; if (pExt861 == NULL || pRawInfo == NULL) { return; } if (flag == FROM_CTA861_EXTENSION || flag == FROM_DISPLAYID_13_DATA_BLOCK) { pInfo = (NVT_EDID_INFO *)pRawInfo; pHdr10PlusInfo = &pInfo->hdr10PlusInfo; } else if (flag == FROM_DISPLAYID_20_DATA_BLOCK) { pDisplayID20 = (NVT_DISPLAYID_2_0_INFO *)pRawInfo; pHdr10PlusInfo = &pDisplayID20->cta.hdr10PlusInfo; } else { return; } if(pExt861->vsvdb.ieee_id != NVT_CEA861_HDR10PLUS_IEEE_ID) { return; } NVMISC_MEMSET(pHdr10PlusInfo, 0, sizeof(NVT_HDR10PLUS_INFO)); if (pExt861->vsvdb.vendor_data_size < sizeof(NVT_HDR10PLUS_INFO)) { return; } NVMISC_MEMCPY(pHdr10PlusInfo, &pExt861->vsvdb.vendor_data, sizeof(NVT_HDR10PLUS_INFO)); } POP_SEGMENTS