Files
open-gpu-kernel-modules/src/common/modeset/timing/nvt_edidext_861.c
Bernhard Stoeckner 91676d6628 550.40.07
2024-01-24 18:28:48 +01:00

4080 lines
187 KiB
C

//*****************************************************************************
//
// SPDX-FileCopyrightText: Copyright (c) 2023 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}}
#define RID_MODE(hv, hsp, vv, vsp, ip, aspect, rid) \
{hv, (hsp)=='-', vv, (vsp)=='-',(ip)=='i'? NVT_INTERLACED:NVT_PROGRESSIVE,((1?aspect)<<16)|(0?aspect), rid}
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_RID_CODES RID[] =
{
RID_MODE( 0, '+', 0, '+', 'p', 16:9 , 0), // No Resolution Identification Available
RID_MODE( 1280, '+', 720, '+', 'p', 16:9 , 1), // HD, 720p
RID_MODE( 1280, '+', 720, '+', 'p', 64:27, 2), // HD, 720p, 21:9 anamorphic
RID_MODE( 1680, '+', 720, '+', 'p', 64:27, 3), // 21:9 "1.5k"
RID_MODE( 1920, '+', 1080, '+', 'p', 16:9 , 4), // Full HD, 1080p
RID_MODE( 1929, '+', 1080, '+', 'p', 64:27, 5), // Full HD, 1080p, 21:9 anamorphic
RID_MODE( 2560, '+', 1080, '+', 'p', 64:27, 6), // 21:9 "2.5k"
RID_MODE( 3840, '+', 1080, '+', 'p', 32:9 , 7), // 32:9 "4K"
RID_MODE( 2560, '+', 1440, '+', 'p', 16:9 , 8), // QHD, 1440p
RID_MODE( 3440, '+', 1440, '+', 'p', 64:27, 9), // WQHD
RID_MODE( 5120, '+', 1440, '+', 'p', 32:9 ,10), // 32:9 5k
RID_MODE( 3840, '+', 2160, '+', 'p', 16:9 ,11), // HD "4K", 2160p
RID_MODE( 3840, '+', 2160, '+', 'p', 64:27,12), // UHD "4K", 2160p, 21:9 anamorphic
RID_MODE( 5120, '+', 2160, '+', 'p', 64:27,13), // 21:9 "5K"
RID_MODE( 7680, '+', 2160, '+', 'p', 32:9 ,14), // 32:9 "8K"
RID_MODE( 5120, '+', 2880, '+', 'p', 16:9 ,15), // 2880p
RID_MODE( 5120, '+', 2880, '+', 'p', 64:27,16), // 2880p, 21:9 anamorphic
RID_MODE( 6880, '+', 2880, '+', 'p', 64:27,17), // 21:9 "6K"
RID_MODE(10240, '+', 2880, '+', 'p', 32:9 ,18), // 32:9 "10K"
RID_MODE( 7680, '+', 4320, '+', 'p', 16:9 ,19), // UHD "8K", 4320p
RID_MODE( 7680, '+', 4320, '+', 'p', 64:27,20), // UHD "8K", 4320p, 21:9 anamorphic
RID_MODE(10240, '+', 4320, '+', 'p', 64:27,21), // 21:9 "10K"
RID_MODE(15360, '+', 4320, '+', 'p', 32:9 ,22), // 32:9 "15K"
RID_MODE(11520, '+', 6480, '+', 'p', 16:9 ,23), // UHD "12K", 6480p
RID_MODE(11520, '+', 6480, '+', 'p', 64:27,24), // UHD "12K", 6480p, 21:9 anamorphic
RID_MODE(15360, '+', 6480, '+', 'p', 64:27,25), // 21:9 "15K"
RID_MODE(15360, '+', 8640, '+', 'p', 16:9 ,26), // UHD "16K", 8640p
RID_MODE(15360, '+', 8640, '+', 'p', 64:27,27), // UHD "16K", 8640p, 21:9 anamorphic
RID_MODE(20480, '+', 8640, '+', 'p', 64:27,28) // 21:9 "20K"
// 29...63 Reserved for future
};
static NvU32 MAX_RID_CODES_COUNT = sizeof(RID) / sizeof(RID[0]) - 1;
// RID to VIC Mapping
static const NvU8 RID_VIC_MAP[][8] =
{
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 60, 61, 62, 108, 19, 4, 41, 47 }, // RID 01
{ 65, 66, 67, 109, 68, 69, 70, 71 }, // RID 02
{ 79, 80, 81, 110, 82, 83, 84, 85 }, // RID 03
{ 32, 33, 34, 111, 31, 16, 64, 63 }, // RID 04
{ 72, 73, 74, 112, 75, 76, 77, 78 }, // RID 05
{ 86, 87, 88, 113, 89, 90, 91, 92 }, // RID 06
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 93, 94, 95, 114, 96, 97, 117, 118 }, // RID 11
{ 103, 104, 105, 116, 106, 107, 119, 120 }, // RID 12
{ 121, 122, 123, 124, 125, 126, 127, 193 }, // RID 13
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 194, 195, 196, 197, 198, 199, 200, 201 }, // RID 19
{ 202, 203, 204, 205, 206, 207, 208, 209 }, // RID 20
{ 210, 211, 212, 213, 214, 215, 216, 217 }, // RID 21
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
};
// All the frame rate supported in VF
static const NvU16 VF_FRAME_RATE[] =
{
0, 24, 25, 30, 48, 50, 60, 100, 120, 144, 200, 240, 300, 360, 400, 480
};
static NvU8 MAX_VF_FRAME_RATE_COUNT = sizeof(VF_FRAME_RATE) / sizeof (VF_FRAME_RATE[0])-1;
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, /*byte14~15*/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};
CODE_SEGMENT(PAGE_DD_CODE)
static NvU8
getExistedCTATimingSeqNumber(
NVT_EDID_INFO *pInfo,
enum NVT_TIMING_TYPE timingType)
{
NvU8 count = 0;
NvU8 i = 0;
switch (timingType)
{
case NVT_TYPE_CTA861_DID_T7:
case NVT_TYPE_CTA861_DID_T8:
case NVT_TYPE_CTA861_DID_T10:
case NVT_TYPE_EDID_861ST:
break;
default:
return count;
}
for (i = 0; i< pInfo->total_timings; i++)
{
if (timingType == NVT_TYPE_EDID_861ST)
{
if (NVT_TIMING_IS_OVT(pInfo->timing[i].etc.flag))
++count;
}
else if (NVT_GET_TIMING_STATUS_TYPE(pInfo->timing[i].etc.status) == timingType)
{
++count;
}
}
return count;
}
CODE_SEGMENT(PAGE_DD_CODE)
static NvBool isVFDRefreshRate(NvU8 vfdSize, NvU8 *vfd, NvU8 rateIdx)
{
NvU8 rid, factor, i;
NvU16 rr;
NvBool bFR24, bFR48, bBFR50, bBFR60, bFR144, bFRFactor;
// frame rate factor {0.5x, 1x, 2x, 4x, 6x, 8x} x 2
const NvU8 frame_rate_factors[6] = { 1, 2, 4, 8, 12, 16 };
rr = VF_FRAME_RATE[rateIdx];
factor = 0;
rid = ((const VFD_ONE_BYTE*)vfd)->rid;
if (rid == 0) return NV_FALSE;
bBFR50 = ((const VFD_ONE_BYTE*)vfd)->bfr50;
// frame rate factor
// If Byte 2 is not present in the VFD, flags 0.5X, 1X and BFR60 shall be considered set
bBFR60 = vfdSize > 1 ? ((const VFD_TWO_BYTE*)vfd)->bfr60 : 1;
bFRFactor = vfdSize > 1 ? ((const VFD_TWO_BYTE*)vfd)->frRate : 3;
// individual frame rate
bFR24 = ((const VFD_ONE_BYTE*)vfd)->fr24;
if (rr == 24) return bFR24;
// individual frame rate
bFR48 = vfdSize > 2 ? ((const VFD_THREE_BYTE*)vfd)->fr48 : 0;
if (rr == 48) return bFR48;
// individual frame rate
bFR144 = vfdSize > 1 ? ((const VFD_TWO_BYTE*)vfd)->fr144 : 0;
if (rr == 144) return bFR144;
if (rr % (50/2) == 0)
{
if (!bBFR50) return NV_FALSE;
factor = rr / 25;
}
else if (rr % (60/2) == 0)
{
if (!bBFR60) return NV_FALSE;
factor = rr / 30;
}
for (i = 0; i < COUNT(frame_rate_factors); i++)
{
if (frame_rate_factors[i] == factor)
{
if (bFRFactor & (1 << i))
return NV_TRUE;
else
break;
}
}
return NV_FALSE;
}
// 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)) &&
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;
}
}
}
}
CODE_SEGMENT(PAGE_DD_CODE)
void parseCta861VideoFormatDataBlock(NVT_EDID_CEA861_INFO *pExt861, void *pRawInfo)
{
NvU8 i = 0;
NvU8 rateIdx = 0;
NvU8 vfdb_idx = 0;
NvU8 startSeqNum = 0;
NvU8 eachOfDescSize = 0;
NvU32 width = 0;
NvU32 height = 0;
const VFD_ONE_BYTE *pVFDOneByte = 0 ;
NVT_TIMING newTiming;
NVT_EDID_INFO *pInfo = (NVT_EDID_INFO *)pRawInfo;
for (vfdb_idx = 0; vfdb_idx < pExt861->total_vfdb; vfdb_idx++)
{
eachOfDescSize = pExt861->vfdb[vfdb_idx].info.vfd_len + 1;
if (eachOfDescSize == 0)
{
nvt_assert(0 && "Video Format Descriptor length is 0!\n");
return;
}
for (i = 0; i < pExt861->vfdb[vfdb_idx].total_vfd; i++)
{
// data block value sanity check:
if (eachOfDescSize > 2 && (((const VFD_THREE_BYTE*)&pExt861->vfdb[vfdb_idx].video_format_desc[i*eachOfDescSize])->f31_37 != 0))
nvt_assert(0 && "F31-F37 bits does not be 0 in Byte3!.\n");
if (eachOfDescSize > 3 && ((const VFD_FOUR_BYTE*)&pExt861->vfdb[vfdb_idx].video_format_desc[i*eachOfDescSize])->f40_47 !=0)
nvt_assert(0 && "It is not support yet in Byte4!");
pVFDOneByte = (const VFD_ONE_BYTE *)&pExt861->vfdb[vfdb_idx].video_format_desc[i*eachOfDescSize];
/*
* If any of the following is true, then the RID shall be set to 0:
* 1. If a Video Format not listed in "Table 12 - Resolution Identification (RID) is sent
* 2. if a Video Format with Frame Rates not listed in "Table 13 - AVI InfoFrame Video Format Frame Rate" is sent
* 3. if a Video Format listed in "Table 14 - RID To VIC Mapping" is sent.
*/
// For 1.
if ((pVFDOneByte->rid & NVT_CTA861_VF_RID_MASK) == 0 || pVFDOneByte->rid > MAX_RID_CODES_COUNT)
{
nvt_assert(0 && "shall have a non-zero RID value or RID code value larger than 28");
continue;
}
width = RID[pVFDOneByte->rid].HVisible;
height = RID[pVFDOneByte->rid].VVisible;
// If the Source is sending a Video Format that can be indicated by RID and FR,
// and is not listed in Table 14 (RID to VIC), then it shall set the RID and FR fields to the proper codes
for (rateIdx = 1; rateIdx <= MAX_VF_FRAME_RATE_COUNT; rateIdx++)
{
// For 2.
if (!isVFDRefreshRate(eachOfDescSize, &pExt861->vfdb[vfdb_idx].video_format_desc[i*eachOfDescSize], rateIdx))
{
continue;
}
// For 3.
if (VF_FRAME_RATE[rateIdx] < 144 && RID_VIC_MAP[pVFDOneByte->rid][rateIdx-1])
{
nvt_assert(0 && "RID not allowed since it maps to VIC!");
continue;
}
startSeqNum = getExistedCTATimingSeqNumber(pInfo, NVT_TYPE_EDID_861ST);
NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
if (NvTiming_CalcOVT(width, height, VF_FRAME_RATE[rateIdx], &newTiming) == NVT_STATUS_SUCCESS)
{
if (pExt861->vfdb[vfdb_idx].info.y420 && newTiming.pclk > NVT_HDMI_YUV_420_PCLK_SUPPORTED_MIN)
{
UPDATE_BPC_FOR_COLORFORMAT(newTiming.etc.yuv420, 0, 1,
pInfo->hdmiForumInfo.dc_30bit_420,
pInfo->hdmiForumInfo.dc_36bit_420, 0,
pInfo->hdmiForumInfo.dc_48bit_420);
}
newTiming.etc.flag |= NVT_FLAG_CTA_OVT_TIMING;
if (pExt861->vfdb[vfdb_idx].info.ntsc)
{
newTiming.etc.flag |= NVT_FLAG_CTA_OVT_FRR_TIMING;
}
newTiming.etc.status = NVT_STATUS_EDID_861STn(++startSeqNum);
NVT_SNPRINTF((char *)newTiming.etc.name, sizeof(newTiming.etc.name), "CTA861-OVT%d:#%3d:%dx%dx%3d.%03dHz/%s",
(int)pVFDOneByte->rid,
(int)NVT_GET_TIMING_STATUS_SEQ(newTiming.etc.status),
(int)newTiming.HVisible,
(int)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 (!assignNextAvailableTiming(pInfo, &newTiming))
{
continue;
}
}
else
{
continue;
}
}
}
}
}
// 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, the SVR both used in the NVRDB and VFPDB.
// "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 parseCta861NativeOrPreferredTiming(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 nativeSvr = 0;
NvU8 *pSvr = pExt861->svr_vfpdb;
NvU8 totalSvr = pExt861->total_svr;
NvU8 kth = 0;
NvU8 extKth = 0;
NvU8 DTDCount = 0;
NvU8 extDTDCount = 0;
NvU8 DIDT7Count = 0;
NvU8 DIDT10Count = 0;
NvU8 OVTCount = 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 in Base 0 or CTA861
if (flag == FROM_CTA861_EXTENSION)
{
// get the NVRDB, from the spec this native resolution has more high priority than others
if (pExt861->valid.NVRDB == 1)
{
nativeSvr = pExt861->native_video_resolution_db.native_svr;
totalSvr = 1;
}
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++;
else if (NVT_IS_CTA861_DID_T7(pInfo->timing[j].etc.status)) DIDT7Count++;
else if (NVT_IS_CTA861_DID_T10(pInfo->timing[j].etc.status)) DIDT10Count++;
else if (NVT_TIMING_IS_OVT(pInfo->timing[j].etc.flag)) OVTCount++;
}
}
// this only handles single SVR
for (i = 0; i < totalSvr; i++)
{
NvU8 svr = 0;
NvU8 vic = 0;
if (pExt861->valid.NVRDB == 1)
svr = nativeSvr;
else
svr = pSvr[i];
// Reserved
if (svr == 0 || svr == 128 || (svr >= 176 && svr <= 192) || svr == 255)
continue;
// Interpret as the Kth 18-byte DTD, where K = SVR - 128 (for K = 1 to 16) in both base0 and CTA block
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))
break;
}
else
{
extKth = kth - DTDCount;
if (NVT_IS_EXT_DTDn(pInfo->timing[j].etc.status, extKth))
break;
}
}
}
}
else if (svr >= 145 && svr <= 160)
{
// Interpret as the Nth 20-byte DTD or 6- or 7-byte CVT-based descriptor
// where N = SVR - 144 (for N = 1 to 16)
kth = svr - 144;
if (flag == FROM_CTA861_EXTENSION)
{
for (j = 0; j < pInfo->total_timings; j++)
{
if (kth <= DIDT7Count) // pick the Nth 20-byte first
{
if (NVT_IS_CTA861_DID_T7n(pInfo->timing[j].etc.status, kth))
break;
}
else
{
extKth = kth - DIDT7Count; // pick the T10 CVT-based timing then
if (NVT_IS_CTA861_DID_T10n(pInfo->timing[j].etc.status, extKth))
break;
}
}
}
}
else if (svr >= 161 && svr <= 175)
{
// Interpret as the video format indicated by the first VFD of the first VFDB with Frame Rates of Rate Index N
// where N = SVR - 160 (for N = 1 to 15)
kth = svr - 160;
if (flag == FROM_CTA861_EXTENSION)
{
for (j = 0; j < pInfo->total_timings; j++)
{
if (kth <= OVTCount)
{
if (NVT_IS_CTA861_OVT_Tn(pInfo->timing[j].etc.flag, pInfo->timing[j].etc.status, kth))
break;
}
}
}
}
else if (svr == 254)
{
// Interpret as the timing format indicated by the first code of the first T8VTDB
if (flag == FROM_CTA861_EXTENSION)
{
for (j = 0; j < pInfo->total_timings; j++)
{
if (NVT_IS_CTA861_DID_T8_1(pInfo->timing[j].etc.status))
{
kth = 1;
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))
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))
break;
}
}
}
if (flag == FROM_CTA861_EXTENSION || flag == FROM_DISPLAYID_13_DATA_BLOCK)
{
if (pExt861->valid.NVRDB == 1)
pInfo->timing[j].etc.flag |= NVT_FLAG_CTA_NATIVE_TIMING;
else if (vic != 0 || kth != 0)
pInfo->timing[j].etc.flag |= NVT_FLAG_CTA_PREFERRED_TIMING;
}
else if (flag == FROM_DISPLAYID_20_DATA_BLOCK)
{
if (pExt861->valid.NVRDB == 1)
pDisplayID20->timing[j].etc.flag |= NVT_FLAG_CTA_NATIVE_TIMING | NVT_FLAG_DISPLAYID_2_0_TIMING;
else if (vic !=0 || kth != 0)
pDisplayID20->timing[j].etc.flag |= NVT_FLAG_CTA_PREFERRED_TIMING | NVT_FLAG_DISPLAYID_2_0_TIMING;
}
}
}
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 parseCta861DvStaticMetadataDataBlock(VSVDB_DATA* pVsvdb, NVT_DV_STATIC_METADATA *pDvInfo)
{
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;
if (pVsvdb == NULL || pDvInfo == NULL)
{
return;
}
if(pVsvdb->ieee_id != NVT_CEA861_DV_IEEE_ID)
{
return;
}
//init
NVMISC_MEMSET(pDvInfo, 0, sizeof(NVT_DV_STATIC_METADATA));
// copy ieee id
pDvInfo->ieee_id = pVsvdb->ieee_id;
vsvdbVersion = (pVsvdb->vendor_data[0] & NVT_CEA861_VSVDB_VERSION_MASK) >> NVT_CEA861_VSVDB_VERSION_MASK_SHIFT;
switch (vsvdbVersion)
{
case 0:
if (pVsvdb->vendor_data_size < sizeof(NVT_DV_STATIC_METADATA_TYPE0))
{
return;
}
pDvType0 = (NVT_DV_STATIC_METADATA_TYPE0 *)(&pVsvdb->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 (pVsvdb->vendor_data_size == sizeof(NVT_DV_STATIC_METADATA_TYPE1))
{
pDvType1 = (NVT_DV_STATIC_METADATA_TYPE1 *)(&pVsvdb->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 (pVsvdb->vendor_data_size == sizeof(NVT_DV_STATIC_METADATA_TYPE1_1))
{
pvDvType1_1 = (NVT_DV_STATIC_METADATA_TYPE1_1 *)(&pVsvdb->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 (pVsvdb->vendor_data_size < sizeof(NVT_DV_STATIC_METADATA_TYPE2))
{
return;
}
pDvType2 = (NVT_DV_STATIC_METADATA_TYPE2 *)(&pVsvdb->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);
}
}
// parse vendor specific video data block (VSVDB) information
CODE_SEGMENT(PAGE_DD_CODE)
void parseCta861VsvdbBlocks(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_DV_STATIC_METADATA *pDvInfo = 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;
pDvInfo = &pInfo->dv_static_metadata_info;
pHdr10PlusInfo = &pInfo->hdr10PlusInfo;
}
else if (flag == FROM_DISPLAYID_20_DATA_BLOCK)
{
pDisplayID20 = (NVT_DISPLAYID_2_0_INFO *)pRawInfo;
pDvInfo = &pDisplayID20->cta.dvInfo;
pHdr10PlusInfo = &pDisplayID20->cta.hdr10PlusInfo;
}
else
{
return;
}
if (pDvInfo == NULL || pHdr10PlusInfo == NULL || (pExt861->total_vsvdb == 0))
{
return;
}
for (i = 0; i < pExt861->total_vsvdb; i++)
{
// Assumes each vsvdb is unique for this CEA block, e.g., no two HDMI_IEEE_ID
switch (pExt861->vsvdb[i].ieee_id)
{
case NVT_CEA861_DV_IEEE_ID:
// parse Dolby Vision related information from the DV vendor specific video data block
parseCta861DvStaticMetadataDataBlock(&pExt861->vsvdb[i], pDvInfo);
pExt861->valid.dv_static_metadata = 1;
break;
case NVT_CEA861_HDR10PLUS_IEEE_ID:
// parse HDR10+ related information from the HDR10+ LLC Vendor Specific Video Data Block
parseCta861Hdr10PlusDataBlock(&pExt861->vsvdb[i], pHdr10PlusInfo);
pExt861->valid.hdr10Plus = 1;
break;
}
}
}
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 vsvdb_index = 0;
NvU32 yuv420vdb_index = 0;
NvU32 yuv420cmdb_index = 0;
NvU8 vfd_index = 0;
NvU8 didT7_index = 0;
NvU8 didT8_index = 0;
NvU8 didT10_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))
{
break;
}
// 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:
break;
case NVT_CTA861_TAG_VIDEO_FORMAT:
if (payload < 2) return NVT_STATUS_ERR; // no VFD
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_CTA861_EXT_TAG_HF_EEODB && payload != 2) return NVT_STATUS_ERR;
else if (ext_tag == NVT_CTA861_EXT_TAG_DID_TYPE_VII && payload <= 2) return NVT_STATUS_ERR;
else if (ext_tag == NVT_CTA861_EXT_TAG_DID_TYPE_VIII && payload <= 2) return NVT_STATUS_ERR;
else if (ext_tag == NVT_CTA861_EXT_TAG_DID_TYPE_X && payload <= 2) return NVT_STATUS_ERR;
else if (ext_tag == NVT_CTA861_EXT_TAG_NATIVE_VIDEO_RESOLUTION)
{
if (payload != 2 && payload != 3 && payload != 7) return NVT_STATUS_ERR;
}
if (payload > 2)
{
if (ext_tag == NVT_CTA861_EXT_TAG_DID_TYPE_VII)
{
if ((payload-2) != 20) return NVT_STATUS_ERR; // only support 20-bytes
if ((p[i+1] & 0x7) != 2) return NVT_STATUS_ERR; // Block Revision shall be 2
if ((p[i+1] & 0x70) >> 4 != 0) return NVT_STATUS_ERR; // Not allow extra byte
}
else if (ext_tag == NVT_CTA861_EXT_TAG_DID_TYPE_VIII)
{
if ((payload-2) < 1) return NVT_STATUS_ERR; // minimum one code supported
if ((p[i+1] & 0x7) != 1) return NVT_STATUS_ERR; // Block Revision shall be 1
if ((p[i+1] & 0xC0) >> 6 != 0) return NVT_STATUS_ERR; // Not allow others than DMT Timing
}
else if (ext_tag == NVT_CTA861_EXT_TAG_DID_TYPE_X)
{
if ((p[i+1] & 0x7) != 0) return NVT_STATUS_ERR; // Block Revision shall be 0
if (((p[i+1] & 0x70) >> 4 == 0) && (payload-2) % 6) return NVT_STATUS_ERR; // supported 6-bytes descriptors
if (((p[i+1] & 0x70) >> 4 == 1) && (payload-2) % 7) return NVT_STATUS_ERR; // supported 7-bytes descriptors
}
}
}
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_CTA861_TAG_VIDEO_FORMAT)
{
p861info->vfdb[vfd_index].info.vfd_len = p[i] & 0x03;
p861info->vfdb[vfd_index].info.ntsc = (p[i] & 0x40) >> 6;
p861info->vfdb[vfd_index].info.y420 = (p[i] & 0x80) >> 7;
p861info->vfdb[vfd_index].total_vfd = (NvU8)(payload - 1) / (p861info->vfdb[vfd_index].info.vfd_len + 1);
i++; payload--;
for (j = 0; j < payload; j++, i++)
{
p861info->vfdb[vfd_index].video_format_desc[j] = p[i];
}
p861info->total_vfdb = ++vfd_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_svr = 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)
{
if (vsvdb_index < NVT_CEA861_VSVDB_MAX_BLOCKS)
{
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[vsvdb_index].ieee_id = ieee_id;
p861info->vsvdb[vsvdb_index].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[vsvdb_index].vendor_data[j] = p[i];
}
}
vsvdb_index++;
p861info->total_vsvdb = (NvU8)vsvdb_index;
}
else
{
// skip the unsupported extended block
i += payload;
}
}
else
{
// skip the extended block that we don't have a room for,
// the NVT_CEA861_VSVDB_MAX_BLOCKS should be incremented for new VSVDB types
nvt_assert(vsvdb_index >= NVT_CEA861_VSVDB_MAX_BLOCKS);
i += payload;
}
}
else if (ext_tag == NVT_CTA861_EXT_TAG_NATIVE_VIDEO_RESOLUTION)
{
if (payload != 2 && payload != 3 && payload != 7) break;
i++; payload--;
p861info->native_video_resolution_db.native_svr = p[i];
p861info->valid.NVRDB = 1;
i++; payload--;
if (payload != 0)
{
p861info->native_video_resolution_db.option.img_size = p[i] & 0x01;
p861info->native_video_resolution_db.option.sz_prec = (p[i] & 0x80) >> 7;
i++; payload--;
if (p861info->native_video_resolution_db.option.img_size == 1)
{
for (j = 0; j< payload; j++, i++)
{
p861info->native_video_resolution_db.image_size[j] = p[i];
}
}
}
}
else if (ext_tag == NVT_CTA861_EXT_TAG_DID_TYPE_VII)
{
if( payload != 22) break;
i++; payload--;
p861info->did_type7_data_block[didT7_index].version.revision = p[i] & 0x07;
p861info->did_type7_data_block[didT7_index].version.dsc_pt = (p[i] & 0x08) >> 3;
p861info->did_type7_data_block[didT7_index].version.t7_m = (p[i] & 0x70) >> 4;
//do not consider Byte 3
i++; payload--;
p861info->did_type7_data_block[didT7_index].total_descriptors =
(NvU8)(payload / (NVT_CTA861_DID_TYPE7_DESCRIPTORS_LENGTH + p861info->did_type7_data_block[didT7_index].version.t7_m));
for (j = 0; j < payload; j++, i++)
{
p861info->did_type7_data_block[didT7_index].payload[j] = p[i];
}
// next type7 data block if it exists
p861info->total_did_type7db = ++didT7_index;
}
else if (ext_tag == NVT_CTA861_EXT_TAG_DID_TYPE_VIII)
{
if (payload <= 2) break;
i++; payload--;
p861info->did_type8_data_block[didT8_index].version.revision = p[i] & 0x07;
p861info->did_type8_data_block[didT8_index].version.tcs = (p[i] & 0x08) >> 3;
p861info->did_type8_data_block[didT8_index].version.t8y420 = (p[i] & 0x20) >> 5;
p861info->did_type8_data_block[didT8_index].version.code_type = (p[i] & 0xC0) >> 6;
//do not consider Byte 3
i++; payload--;
if (p861info->did_type8_data_block[didT8_index].version.tcs == 0)
p861info->did_type8_data_block[didT8_index].total_descriptors = (NvU8)payload;
else if (p861info->did_type8_data_block[didT8_index].version.tcs == 1)
p861info->did_type8_data_block[didT8_index].total_descriptors = (NvU8)(payload / 2);
for (j = 0; j < payload; j++, i++)
{
p861info->did_type8_data_block[didT8_index].payload[j] = p[i];
}
// next type7 data block if it exists
p861info->total_did_type8db = ++didT8_index;
}
else if (ext_tag == NVT_CTA861_EXT_TAG_DID_TYPE_X)
{
if (payload < 8 || ((payload-2) % 6 != 0 && (payload-2) % 7 != 0)) break;
i++; payload--;
p861info->did_type10_data_block[didT10_index].version.revision = p[i] & 0x07;
p861info->did_type10_data_block[didT10_index].version.t10_m = (p[i] & 0x70) >> 4;
// do not consider Byte 3
i++; payload--;
if (p861info->did_type10_data_block[didT10_index].version.t10_m == 0)
p861info->did_type10_data_block[didT10_index].total_descriptors = (NvU8)(payload / 6);
else if (p861info->did_type10_data_block[didT10_index].version.t10_m == 1)
p861info->did_type10_data_block[didT10_index].total_descriptors = (NvU8)(payload / 7);
for (j = 0; j < payload; j++, i++)
{
p861info->did_type10_data_block[didT10_index].payload[j] = p[i];
}
// next type10 data block if it exists
p861info->total_did_type10db = ++didT10_index;
}
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_CTA861_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;
}
}
if (p861info)
{
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_FRR_TIMING_IS_OVT(pTiming->etc.flag) || NVT_TIMING_IS_OVT(pTiming->etc.flag)) &&
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;
}
}
}
// setup RID code
if (pCtrl->rid == NVT_INFOFRAME_CTRL_DONTCARE)
{
if (NVT_TYPE_EDID_861ST == NVT_GET_TIMING_STATUS_TYPE(pTiming->etc.status) &&
NVT_TIMING_IS_OVT(pTiming->etc.flag))
{
NvU8 ridIdx = 0;
// get the correct rid from the name string = CTA861-OVT'%d':xxx
// %d value shall included two digital or one digital character
if (pTiming->etc.name[11] == ':')
{
ridIdx = pTiming->etc.name[10] - '0';
}
else
{
ridIdx = 10 * (pTiming->etc.name[10] - '0') + (pTiming->etc.name[11] - '0');
}
if (ridIdx > NVT_CTA861_RID_1280x720p_16x9 &&
ridIdx < NVT_CTA861_RID_20480x8640p_64x27)
{
pCtrl->rid = ridIdx;
}
else
{
pCtrl->rid = NVT_INFOFRAME_CTRL_DONTCARE;
}
}
}
// setup Video Format Frame Rate
if (pCtrl->rid != NVT_INFOFRAME_CTRL_DONTCARE)
{
switch (pTiming->etc.rr)
{
case 24:
pCtrl->frame_rate = NVT_CTA861_FR_2400;
if (NVT_FRR_TIMING_IS_OVT(pTiming->etc.flag))
{
pCtrl->frame_rate = NVT_CTA861_FR_2398;
}
break;
case 25:
pCtrl->frame_rate = NVT_CTA861_FR_2500;
break;
case 30:
pCtrl->frame_rate = NVT_CTA861_FR_3000;
if (NVT_FRR_TIMING_IS_OVT(pTiming->etc.flag))
{
pCtrl->frame_rate = NVT_CTA861_FR_2997;
}
break;
case 48:
pCtrl->frame_rate = NVT_CTA861_FR_48000;
if (NVT_FRR_TIMING_IS_OVT(pTiming->etc.flag))
{
pCtrl->frame_rate = NVT_CTA861_FR_4795;
}
break;
case 50:
pCtrl->frame_rate = NVT_CTA861_FR_5000;
break;
case 60:
pCtrl->frame_rate = NVT_CTA861_FR_6000;
if (NVT_FRR_TIMING_IS_OVT(pTiming->etc.flag))
{
pCtrl->frame_rate = NVT_CTA861_FR_5994;
}
break;
case 100:
pCtrl->frame_rate = NVT_CTA861_FR_10000;
break;
case 120:
pCtrl->frame_rate = NVT_CTA861_FR_12000;
if (NVT_FRR_TIMING_IS_OVT(pTiming->etc.flag))
{
pCtrl->frame_rate = NVT_CTA861_FR_11988;
}
break;
case 144:
pCtrl->frame_rate = NVT_CTA861_FR_14400;
if (NVT_FRR_TIMING_IS_OVT(pTiming->etc.flag))
{
pCtrl->frame_rate = NVT_CTA861_FR_14386;
}
break;
case 200:
pCtrl->frame_rate = NVT_CTA861_FR_20000;
break;
case 240:
pCtrl->frame_rate = NVT_CTA861_FR_24000;
if (NVT_FRR_TIMING_IS_OVT(pTiming->etc.flag))
{
pCtrl->frame_rate = NVT_CTA861_FR_23976;
}
break;
case 300:
pCtrl->frame_rate = NVT_CTA861_FR_30000;
break;
case 360:
pCtrl->frame_rate = NVT_CTA861_FR_36000;
if (NVT_FRR_TIMING_IS_OVT(pTiming->etc.flag))
{
pCtrl->frame_rate = NVT_CTA861_FR_35964;
}
break;
case 400:
pCtrl->frame_rate = NVT_CTA861_FR_40000;
break;
case 480:
pCtrl->frame_rate = NVT_CTA861_FR_48000;
if (NVT_FRR_TIMING_IS_OVT(pTiming->etc.flag))
{
pCtrl->frame_rate = NVT_CTA861_FR_47952;
}
break;
default:
pCtrl->frame_rate = NVT_INFOFRAME_CTRL_DONTCARE;
break;
}
}
// 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;
// see 6.4 Format of Version 2, 3, and 4 AVI InfoFrames in CTA861-I
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_YCbCr420) // this shall be as 0 always.
{
if ((pCtrl->rid != NVT_CTA861_RID_NONE) || (pCtrl->frame_rate != NVT_CTA861_FR_NO_DATA))
{
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.
pInfoFrame->length = sizeof(NVT_VIDEO_INFOFRAME) - sizeof(NVT_INFOFRAME_HEADER); // Length == 15
}
else
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.
pInfoFrame->length = 14;
}
else
{
pInfoFrame->version = (((pCtrl->video_format_id & NVT_VIDEO_INFOFRAME_BYTE4_VIC7) != 0) ? NVT_VIDEO_INFOFRAME_VERSION_3 :
((pEdidInfo->ext861.revision >= NVT_CEA861_REV_B) ? NVT_VIDEO_INFOFRAME_VERSION_2 : NVT_VIDEO_INFOFRAME_VERSION_1));
pInfoFrame->length = 13;
}
}
else // Y=7, the IDO defineds the C, EC, ACE fileds. In the case the Source shall set the AVI InforFrame Version filed to no less than 3
{
pInfoFrame->version = NVT_VIDEO_INFOFRAME_VERSION_4;
pInfoFrame->length = 14;
}
}
else
{
pInfoFrame->version = (pEdidInfo->ext861.revision >= NVT_CEA861_REV_B) ? NVT_VIDEO_INFOFRAME_VERSION_2 : NVT_VIDEO_INFOFRAME_VERSION_1;
pInfoFrame->length = 13;
}
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);
}
// byte 14-15
if (pInfoFrame->version >= NVT_VIDEO_INFOFRAME_VERSION_4)
{
if (pCtrl->addition_colorimetry_ext != NVT_INFOFRAME_CTRL_DONTCARE)
{
nvt_nvu8_set_bits(pInfoFrame->byte14, pCtrl->addition_colorimetry_ext, NVT_VIDEO_INFOFRAME_BYTE14_ACE0_3_MASK, NVT_VIDEO_INFOFRAME_BYTE14_ACE0_3_SHIFT);
}
if (pCtrl->frame_rate != NVT_INFOFRAME_CTRL_DONTCARE)
{
// Frame rate
nvt_nvu8_set_bits(pInfoFrame->byte14, pCtrl->frame_rate, NVT_VIDEO_INFOFRAME_BYTE14_FR0_FR3_MASK, NVT_VIDEO_INFOFRAME_BYTE14_FR0_FR3_SHIFT);
pInfoFrame->byte15 &= NVT_VIDEO_INFOFRAME_BYTE15_FR4_MASK^0xFFU;
pInfoFrame->byte15 |= ((pCtrl->frame_rate & NVT_VIDEO_INFOFRAME_BYTE14_FR4_ONE_BIT_MASK) << NVT_VIDEO_INFOFRAME_BYTE15_FR4_SHIFT) & NVT_VIDEO_INFOFRAME_BYTE15_FR4_MASK;
}
if (pCtrl->rid != NVT_INFOFRAME_CTRL_DONTCARE)
{
// RID
nvt_nvu8_set_bits(pInfoFrame->byte15, pCtrl->rid, NVT_VIDEO_INFOFRAME_BYTE15_RID_MASK, NVT_VIDEO_INFOFRAME_BYTE15_RID_SHIFT);
}
}
else // version 2 or 3
{
pInfoFrame->byte14 = 0;
pInfoFrame->byte15 = 0;
}
}
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 || pCtrl == 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
nvt_nvu8_set_bits(pInfoFrame->Header.type, NVT_HDMI_VS_HB0_VALUE, NVT_HDMI_VS_HB0_MASK, NVT_HDMI_VS_HB0_SHIFT);
nvt_nvu8_set_bits(pInfoFrame->Header.version, NVT_HDMI_VS_HB1_VALUE, NVT_HDMI_VS_HB1_MASK, NVT_HDMI_VS_HB1_SHIFT);
nvt_nvu8_set_bits(pInfoFrame->Header.length, NVT_HDMI_VS_HB2_VALUE, NVT_HDMI_VS_HB2_MASK, NVT_HDMI_VS_HB2_SHIFT);
if (pCtrl->HDMIRevision == 14)
{
nvt_nvu8_set_bits(pInfoFrame->Data.byte1, NVT_HDMI_VS_BYTE1_OUI_VER_1_4, NVT_HDMI_VS_BYTE1_OUI_MASK, NVT_HDMI_VS_BYTE1_OUI_SHIFT);
nvt_nvu8_set_bits(pInfoFrame->Data.byte2, NVT_HDMI_VS_BYTE2_OUI_VER_1_4, NVT_HDMI_VS_BYTE2_OUI_MASK, NVT_HDMI_VS_BYTE2_OUI_SHIFT);
nvt_nvu8_set_bits(pInfoFrame->Data.byte3, NVT_HDMI_VS_BYTE3_OUI_VER_1_4, NVT_HDMI_VS_BYTE3_OUI_MASK, NVT_HDMI_VS_BYTE3_OUI_SHIFT);
}
else if (pCtrl->HDMIRevision >= 20)
{
nvt_nvu8_set_bits(pInfoFrame->Data.byte1, NVT_HDMI_VS_BYTE1_OUI_VER_2_0, NVT_HDMI_VS_BYTE1_OUI_MASK, NVT_HDMI_VS_BYTE1_OUI_SHIFT);
nvt_nvu8_set_bits(pInfoFrame->Data.byte2, NVT_HDMI_VS_BYTE2_OUI_VER_2_0, NVT_HDMI_VS_BYTE2_OUI_MASK, NVT_HDMI_VS_BYTE2_OUI_SHIFT);
nvt_nvu8_set_bits(pInfoFrame->Data.byte3, NVT_HDMI_VS_BYTE3_OUI_VER_2_0, NVT_HDMI_VS_BYTE3_OUI_MASK, NVT_HDMI_VS_BYTE3_OUI_SHIFT);
}
// 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
// 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;
}
}
if (pCtrl->ALLMEnable == 1)
{
nvt_nvu8_set_bits(pInfoFrame->Data.byte5, NVT_HDMI_VS_BYTE5_ALLM_MODE_EN, NVT_HDMI_VS_BYTE5_ALLM_MODE_MASK, NVT_HDMI_VS_BYTE5_ALLM_MODE_SHIFT);
}
else if (pCtrl->ALLMEnable == 0)
{
nvt_nvu8_set_bits(pInfoFrame->Data.byte5, NVT_HDMI_VS_BYTE5_ALLM_MODE_DIS, NVT_HDMI_VS_BYTE5_ALLM_MODE_MASK, NVT_HDMI_VS_BYTE5_ALLM_MODE_SHIFT);
}
// 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;
if (pCtrl->Sync)
{
nvt_nvu8_set_bits(pInfoFrame->Data.byte1, NVT_HDMI_EMP_BYTE1_SYNC_ENABLE,
NVT_HDMI_EMP_BYTE1_SYNC_MASK,
NVT_HDMI_EMP_BYTE1_SYNC_SHIFT);
}
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 && !pCtrl->EnableQMS)
{
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 || pCtrl->EnableQMS) ? 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);
}
else if (pCtrl->EnableQMS)
{
nvt_nvu8_set_bits(pInfoFrame->Data.metadataBytes[0], pCtrl->MConst,
NVT_HDMI_EMP_BYTE8_MD0_M_CONST_MASK,
NVT_HDMI_EMP_BYTE8_MD0_M_CONST_SHIFT);
nvt_nvu8_set_bits(pInfoFrame->Data.metadataBytes[0],
NVT_HDMI_EMP_BYTE8_MD0_QMS_EN_ENABLE,
NVT_HDMI_EMP_BYTE8_MD0_QMS_EN_MASK,
NVT_HDMI_EMP_BYTE8_MD0_QMS_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);
}
if (pCtrl->version == NVT_EXTENDED_METADATA_PACKET_INFOFRAME_VER_HDMI21A && pCtrl->EnableQMS)
{
nvt_nvu8_set_bits(pInfoFrame->Data.metadataBytes[2],
pCtrl->NextTFR,
NVT_HDMI_EMP_BYTE8_MD2_NEXT_TFR_MASK,
NVT_HDMI_EMP_BYTE8_MD2_NEXT_TFR_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;
}
// Construct Adaptive Sync SDP
CODE_SEGMENT(PAGE_DD_CODE)
void NvTiming_ConstructAdaptiveSyncSDP(
const NVT_ADAPTIVE_SYNC_SDP_CTRL *pCtrl,
NVT_ADAPTIVE_SYNC_SDP *pSdp)
{
if (!pCtrl || !pSdp)
{
return;
}
// Initialize the infoframe
NVMISC_MEMSET(pSdp, 0, sizeof(*pSdp));
// Construct an infoframe to enable or disable Adaptive Sync SDP
pSdp->header.type = NVT_DP_ADAPTIVE_SYNC_SDP_PACKET_TYPE;
pSdp->header.version = NVT_DP_ADAPTIVE_SYNC_SDP_VERSION;
pSdp->header.length = NVT_DP_ADAPTIVE_SYNC_SDP_LENGTH;
// Payload
if (pCtrl->bFixedVTotal)
{
nvt_nvu8_set_bits(pSdp->payload.db0, NVT_DP_ADAPTIVE_SYNC_SDP_DB0_VARIABLE_FRAME_RATE_FAVT_TARGET_REACHED,
NVT_DP_ADAPTIVE_SYNC_SDP_DB0_VARIABLE_FRAME_RATE_MASK,
NVT_DP_ADAPTIVE_SYNC_SDP_DB0_VARIABLE_FRAME_RATE_SHIFT);
if (pCtrl->targetRefreshRate)
{
nvt_nvu8_set_bits(pSdp->payload.db3, pCtrl->targetRefreshRate & 0xff,
NVT_DP_ADAPTIVE_SYNC_SDP_DB3_TARGET_RR_LSB_MASK,
NVT_DP_ADAPTIVE_SYNC_SDP_DB3_TARGET_RR_LSB_SHIFT);
nvt_nvu8_set_bits(pSdp->payload.db4, pCtrl->targetRefreshRate & 0x1,
NVT_DP_ADAPTIVE_SYNC_SDP_DB4_TARGET_RR_MSB_MASK,
NVT_DP_ADAPTIVE_SYNC_SDP_DB4_TARGET_RR_MSB_SHIFT);
}
}
else
{
nvt_nvu8_set_bits(pSdp->payload.db0, NVT_DP_ADAPTIVE_SYNC_SDP_DB0_VARIABLE_FRAME_RATE_AVT_VARIABLE,
NVT_DP_ADAPTIVE_SYNC_SDP_DB0_VARIABLE_FRAME_RATE_MASK,
NVT_DP_ADAPTIVE_SYNC_SDP_DB0_VARIABLE_FRAME_RATE_SHIFT);
}
if (pCtrl->minVTotal)
{
nvt_nvu8_set_bits(pSdp->payload.db1, pCtrl->minVTotal & 0xff,
NVT_DP_ADAPTIVE_SYNC_SDP_DB1_MIN_VTOTAL_LSB_MASK,
NVT_DP_ADAPTIVE_SYNC_SDP_DB1_MIN_VTOTAL_LSB_SHIFT);
nvt_nvu8_set_bits(pSdp->payload.db2, (pCtrl->minVTotal & 0xff00) >> 8,
NVT_DP_ADAPTIVE_SYNC_SDP_DB2_MIN_VTOTAL_MSB_MASK,
NVT_DP_ADAPTIVE_SYNC_SDP_DB2_MIN_VTOTAL_MSB_SHIFT);
}
if (pCtrl->bRefreshRateDivider)
{
nvt_nvu8_set_bits(pSdp->payload.db4, NVT_DP_ADAPTIVE_SYNC_SDP_DB4_TARGET_RR_DIVIDER_ENABLE,
NVT_DP_ADAPTIVE_SYNC_SDP_DB4_TARGET_RR_DIVIDER_MASK,
NVT_DP_ADAPTIVE_SYNC_SDP_DB4_TARGET_RR_DIVIDER_SHIFT);
}
if (pCtrl->srCoastingVTotal)
{
nvt_nvu8_set_bits(pSdp->payload.db7, pCtrl->srCoastingVTotal & 0xff,
NVT_DP_ADAPTIVE_SYNC_SDP_DB7_PR_COASTING_VTOTAL_LSB_MASK,
NVT_DP_ADAPTIVE_SYNC_SDP_DB7_PR_COASTING_VTOTAL_LSB_SHIFT);
nvt_nvu8_set_bits(pSdp->payload.db8, (pCtrl->srCoastingVTotal & 0xff00) >> 8,
NVT_DP_ADAPTIVE_SYNC_SDP_DB8_PR_COASTING_VTOTAL_MSB_MASK,
NVT_DP_ADAPTIVE_SYNC_SDP_DB8_PR_COASTING_VTOTAL_MSB_SHIFT);
}
}
// 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->qms = pHdmiForum->QMS;
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;
pHdmiInfo->qms_tfr_min = pHdmiForum->QMS_TFR_min;
pHdmiInfo->qms_tfr_max = pHdmiForum->QMS_TFR_max;
// 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 parseCta861Hdr10PlusDataBlock(VSVDB_DATA* pVsvdb, NVT_HDR10PLUS_INFO* pHdr10PlusInfo)
{
if (pVsvdb == NULL || pHdr10PlusInfo == NULL)
return;
if(pVsvdb->ieee_id != NVT_CEA861_HDR10PLUS_IEEE_ID)
return;
NVMISC_MEMSET(pHdr10PlusInfo, 0, sizeof(NVT_HDR10PLUS_INFO));
if (pVsvdb->vendor_data_size < sizeof(NVT_HDR10PLUS_INFO))
return;
NVMISC_MEMCPY(pHdr10PlusInfo, &pVsvdb->vendor_data, sizeof(NVT_HDR10PLUS_INFO));
}
CODE_SEGMENT(PAGE_DD_CODE)
void parseCta861DIDType7VideoTimingDataBlock(NVT_EDID_CEA861_INFO *pExt861, void *pRawInfo)
{
NvU8 i = 0;
NvU8 t7db_idx = 0;
NvU8 startSeqNum = 0;
NVT_TIMING newTiming;
NVT_EDID_INFO *pInfo = (NVT_EDID_INFO *)pRawInfo;
const DISPLAYID_2_0_TIMING_7_DESCRIPTOR *pT7Descriptor = NULL;
NvU8 eachOfDescSize = sizeof(DISPLAYID_2_0_TIMING_7_DESCRIPTOR);
for (t7db_idx = 0; t7db_idx < pExt861->total_did_type7db; t7db_idx++)
{
// 20 bytes
eachOfDescSize += pExt861->did_type7_data_block[t7db_idx].version.t7_m;
if (pExt861->did_type7_data_block[t7db_idx].total_descriptors != NVT_CTA861_DID_TYPE7_DESCRIPTORS_MAX)
{
nvt_assert(0 && "payload descriptor invalid. expect T7VTDB only 1 descriptor");
continue;
}
if (pExt861->did_type7_data_block[t7db_idx].version.revision != 2 )
{
nvt_assert(0 && "The revision supported by CTA-861 is not 2");
}
startSeqNum = getExistedCTATimingSeqNumber(pInfo, NVT_TYPE_CTA861_DID_T7);
for (i = 0; i < pExt861->did_type7_data_block[i].total_descriptors; i++)
{
NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
if (NVT_STATUS_SUCCESS == parseDisplayId20Timing7Descriptor(&pExt861->did_type7_data_block[t7db_idx].payload[i*eachOfDescSize],
&newTiming,
startSeqNum+i))
{
// T7VTDB shall not be used with video timing that can be expressed in an 18-byte DTD
if (newTiming.HVisible < 4096 && newTiming.VVisible < 4096 && newTiming.pclk < 65536)
{
nvt_assert(0 && "The timing can be expressed in an 18-byte DTD");
continue;
}
pT7Descriptor = (const DISPLAYID_2_0_TIMING_7_DESCRIPTOR *)
&pExt861->did_type7_data_block[t7db_idx].payload[i*eachOfDescSize];
if (pT7Descriptor->options.is_preferred_or_ycc420 == 1 && newTiming.pclk > NVT_HDMI_YUV_420_PCLK_SUPPORTED_MIN)
{
newTiming.etc.yuv420.bpcs = 0;
UPDATE_BPC_FOR_COLORFORMAT(newTiming.etc.yuv420, 0, 1,
pInfo->hdmiForumInfo.dc_30bit_420,
pInfo->hdmiForumInfo.dc_36bit_420, 0,
pInfo->hdmiForumInfo.dc_48bit_420);
}
NVT_SNPRINTF((char *)newTiming.etc.name, sizeof(newTiming.etc.name), "CTA861-T7:#%3d:%dx%dx%3d.%03dHz/%s",
(int)NVT_GET_TIMING_STATUS_SEQ(newTiming.etc.status),
(int)newTiming.HVisible,
(int)newTiming.VVisible,
(int)newTiming.etc.rrx1k/1000,
(int)newTiming.etc.rrx1k%1000,
(newTiming.interlaced ? "I":"P"));
newTiming.etc.status = NVT_STATUS_CTA861_DID_T7N(NVT_GET_TIMING_STATUS_SEQ(newTiming.etc.status));
newTiming.etc.name[sizeof(newTiming.etc.name) - 1] = '\0';
newTiming.etc.rep = 0x1;
if (!assignNextAvailableTiming(pInfo, &newTiming))
{
break;
}
}
}
}
}
CODE_SEGMENT(PAGE_DD_CODE)
void parseCta861DIDType8VideoTimingDataBlock(NVT_EDID_CEA861_INFO *pExt861, void *pRawInfo)
{
NvU8 i = 0;
NvU8 t8db_idx = 0;
NvU8 startSeqNum = 0;
NvU8 codeSize = 0;
NvU8 codeType = 0;
NVT_TIMING newTiming;
NVT_EDID_INFO *pInfo = (NVT_EDID_INFO *)pRawInfo;
for (t8db_idx = 0; t8db_idx < pExt861->total_did_type8db; t8db_idx++)
{
codeType = pExt861->did_type8_data_block[t8db_idx].version.code_type;
codeSize = pExt861->did_type8_data_block[t8db_idx].version.tcs;
if (codeType != 0 /*DMT*/)
{
nvt_assert(0 && "Not DMT code type!");
continue;
}
startSeqNum = getExistedCTATimingSeqNumber(pInfo, NVT_TYPE_CTA861_DID_T8);
for (i=0; i < pExt861->did_type8_data_block[t8db_idx].total_descriptors; i++)
{
NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
if (parseDisplayId20Timing8Descriptor(pExt861->did_type8_data_block[t8db_idx].payload,
&newTiming, codeType, codeSize, i, startSeqNum + i) == NVT_STATUS_SUCCESS)
{
if (pExt861->did_type8_data_block[t8db_idx].version.t8y420 == 1 && newTiming.pclk > NVT_HDMI_YUV_420_PCLK_SUPPORTED_MIN)
{
UPDATE_BPC_FOR_COLORFORMAT(newTiming.etc.yuv420, 0, 1,
pInfo->hdmiForumInfo.dc_30bit_420,
pInfo->hdmiForumInfo.dc_36bit_420, 0,
pInfo->hdmiForumInfo.dc_48bit_420);
}
NVT_SNPRINTF((char *)newTiming.etc.name, sizeof(newTiming.etc.name), "CTA861-T8:#%3d:%dx%dx%3d.%03dHz/%s",
(int)NVT_GET_TIMING_STATUS_SEQ(newTiming.etc.status),
(int)newTiming.HVisible, (int)newTiming.VVisible,
(int)newTiming.etc.rrx1k/1000, (int)newTiming.etc.rrx1k%1000,
(newTiming.interlaced ? "I":"P"));
newTiming.etc.status = NVT_STATUS_CTA861_DID_T8N(NVT_GET_TIMING_STATUS_SEQ(newTiming.etc.status));
newTiming.etc.name[sizeof(newTiming.etc.name) - 1] = '\0';
newTiming.etc.rep = 0x1;
if (!assignNextAvailableTiming(pInfo, &newTiming))
{
break;
}
}
}
}
}
CODE_SEGMENT(PAGE_DD_CODE)
void parseCta861DIDType10VideoTimingDataBlock(NVT_EDID_CEA861_INFO *pExt861, void *pRawInfo)
{
NvU8 i = 0;
NvU8 t10db_idx = 0;
NvU8 startSeqNum = 0;
NVT_TIMING newTiming;
NVT_EDID_INFO *pInfo = (NVT_EDID_INFO *)pRawInfo;
const DISPLAYID_2_0_TIMING_10_6BYTES_DESCRIPTOR *p6bytesDescriptor = NULL;
NvU8 eachOfDescriptorsSize = sizeof (DISPLAYID_2_0_TIMING_10_6BYTES_DESCRIPTOR);
for (t10db_idx = 0; t10db_idx < pExt861->total_did_type10db; t10db_idx++)
{
startSeqNum = getExistedCTATimingSeqNumber(pInfo, NVT_TYPE_CTA861_DID_T10);
// 6 or 7 bytes length
eachOfDescriptorsSize += pExt861->did_type10_data_block[t10db_idx].version.t10_m;
for (i = 0; i < pExt861->did_type10_data_block[t10db_idx].total_descriptors; i++)
{
if (pExt861->did_type10_data_block[t10db_idx].total_descriptors < NVT_CTA861_DID_TYPE10_DESCRIPTORS_MIN ||
pExt861->did_type10_data_block[t10db_idx].total_descriptors > NVT_CTA861_DID_TYPE10_DESCRIPTORS_MAX)
{
nvt_assert(0 && "payload descriptor invalid. expect T10VTDB has minimum 1 descriptor, maximum 4 descriptors");
continue;
}
NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
if (NVT_STATUS_SUCCESS == parseDisplayId20Timing10Descriptor(&pExt861->did_type10_data_block[t10db_idx].payload[i*eachOfDescriptorsSize],
&newTiming,
pExt861->did_type10_data_block[t10db_idx].version.t10_m, startSeqNum+i))
{
p6bytesDescriptor = (const DISPLAYID_2_0_TIMING_10_6BYTES_DESCRIPTOR *)
&pExt861->did_type10_data_block[t10db_idx].payload[i*eachOfDescriptorsSize];
if (p6bytesDescriptor->options.ycc420_support && newTiming.pclk > NVT_HDMI_YUV_420_PCLK_SUPPORTED_MIN)
{
UPDATE_BPC_FOR_COLORFORMAT(newTiming.etc.yuv420, 0, 1,
pInfo->hdmiForumInfo.dc_30bit_420,
pInfo->hdmiForumInfo.dc_36bit_420, 0,
pInfo->hdmiForumInfo.dc_48bit_420);
}
if (p6bytesDescriptor->options.timing_formula == DISPLAYID_2_0_TIMING_FORMULA_CVT_1_2_STANDARD)
{
NVT_SNPRINTF((char *)newTiming.etc.name, sizeof(newTiming.etc.name), "CTA861-T10:#%3d:%dx%dx%3d.%03dHz/%s",
(int)NVT_GET_TIMING_STATUS_SEQ(newTiming.etc.status),
(int)newTiming.HVisible,
(int)newTiming.VVisible,
(int)newTiming.etc.rrx1k/1000,
(int)newTiming.etc.rrx1k%1000,
(newTiming.interlaced ? "I":"P"));
}
else
{
NVT_SNPRINTF((char *)newTiming.etc.name, sizeof(newTiming.etc.name), "CTA861-T10RB%d:#%3d:%dx%dx%3d.%03dHz/%s",
p6bytesDescriptor->options.timing_formula,
(int)NVT_GET_TIMING_STATUS_SEQ(newTiming.etc.status),
(int)newTiming.HVisible,
(int)newTiming.VVisible,
(int)newTiming.etc.rrx1k/1000,
(int)newTiming.etc.rrx1k%1000,
(newTiming.interlaced ? "I":"P"));
}
newTiming.etc.status = NVT_STATUS_CTA861_DID_T10N(NVT_GET_TIMING_STATUS_SEQ(newTiming.etc.status));
newTiming.etc.name[sizeof(newTiming.etc.name) - 1] = '\0';
newTiming.etc.rep = 0x1;
if (!assignNextAvailableTiming(pInfo, &newTiming))
{
break;
}
}
else
{
continue;
}
}
}
}
POP_SEGMENTS