//***************************************************************************** // // SPDX-FileCopyrightText: Copyright (c) 2021 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_tv.c // // Purpose: calculate tv based timing timing // //***************************************************************************** #include "nvBinSegment.h" #include "nvtiming_pvt.h" PUSH_SEGMENTS CONS_SEGMENT(PAGE_CONS) static const NVT_TIMING TV_TIMING[] = { {720, 0,21,66,894, NVT_H_SYNC_POSITIVE,240, 0,10, 6,262, NVT_V_SYNC_POSITIVE,NVT_INTERLACED, 1407 , 14070, {0,60,59940,0x0403,0x1,{0},{0},{0},{0},NVT_STATUS_SDTV_NTSC_M, "SDTV:NTSC_M"}}, {720, 0,21,66,894, NVT_H_SYNC_POSITIVE,240, 0,10, 6,262, NVT_V_SYNC_POSITIVE,NVT_INTERLACED, 1407 , 14070, {0,60,59940,0x0403,0x1,{0},{0},{0},{0},NVT_STATUS_SDTV_NTSC_J, "SDTV:NTSC_J"}}, {720, 0,21,66,894, NVT_H_SYNC_POSITIVE,288, 0,10, 8,312, NVT_V_SYNC_POSITIVE,NVT_INTERLACED, 1397 , 13970, {0,50,50000,0x0403,0x1,{0},{0},{0},{0},NVT_STATUS_SDTV_PAL_M, "SDTV:PAL_M"}}, {720, 0,21,66,894, NVT_H_SYNC_POSITIVE,288, 0,10, 8,312, NVT_V_SYNC_POSITIVE,NVT_INTERLACED, 1397 , 13970, {0,50,50000,0x0403,0x1,{0},{0},{0},{0},NVT_STATUS_SDTV_PAL_A, "SDTV:PAL_A"}}, {720, 0,21,66,894, NVT_H_SYNC_POSITIVE,288, 0,10, 8,312, NVT_V_SYNC_POSITIVE,NVT_INTERLACED, 1397 , 13970, {0,50,50000,0x0403,0x1,{0},{0},{0},{0},NVT_STATUS_SDTV_PAL_N, "SDTV:PAL_N"}}, {720, 0,21,66,894, NVT_H_SYNC_POSITIVE,288, 0,10, 8,312, NVT_V_SYNC_POSITIVE,NVT_INTERLACED, 1397 , 13970, {0,50,50000,0x0403,0x1,{0},{0},{0},{0},NVT_STATUS_SDTV_PAL_NC, "SDTV:PAL_NC"}}, {720, 0,21,66,894, NVT_H_SYNC_POSITIVE,240, 0,10, 6,262, NVT_V_SYNC_POSITIVE,NVT_INTERLACED, 1407 , 14070, {0,60,59940,0x0403,0x1,{0},{0},{0},{0},NVT_STATUS_HDTV_480I, "HDTV(analog):480i"}}, {720, 0,15,8, 858, NVT_H_SYNC_NEGATIVE,480, 0,10, 4,525, NVT_V_SYNC_NEGATIVE,NVT_PROGRESSIVE, 2700 , 27000, {0,60,59940,0x0403,0x1,{0},{0},{0},{0},NVT_STATUS_HDTV_480P, "HDTV(analog):480p"}}, {720, 0,21,66,894, NVT_H_SYNC_POSITIVE,288, 0,10, 8,312, NVT_V_SYNC_POSITIVE,NVT_INTERLACED, 1397 , 13970, {0,50,50000,0x0403,0x1,{0},{0},{0},{0},NVT_STATUS_HDTV_576I, "HDTV(analog):576i"}}, {720, 0,10,8, 864, NVT_H_SYNC_NEGATIVE,576, 0, 5, 4,625, NVT_V_SYNC_NEGATIVE,NVT_PROGRESSIVE, 2700 , 27000, {0,50,50000,0x0403,0x1,{0},{0},{0},{0},NVT_STATUS_HDTV_576P, "HDTV(analog):576p"}}, {1280,0,70,80, 1650,NVT_H_SYNC_NEGATIVE,720, 0, 5, 5,750, NVT_V_SYNC_NEGATIVE,NVT_PROGRESSIVE, 7418 , 74180, {0,60,59940,0x1009,0x1,{0},{0},{0},{0},NVT_STATUS_HDTV_720P, "HDTV(analog):720p"}}, {1920,0,44,88,2200, NVT_H_SYNC_NEGATIVE,540, 0, 2, 5,562, NVT_V_SYNC_NEGATIVE,NVT_INTERLACED, 7418 , 74180, {0,60,59940,0x1009,0x1,{0},{0},{0},{0},NVT_STATUS_HDTV_1080I, "HDTV(analog):1080i"}}, {1920,0,44,88,2200, NVT_H_SYNC_NEGATIVE,1080,0, 4, 5,1125,NVT_V_SYNC_NEGATIVE,NVT_PROGRESSIVE, 14835,148350, {0,60,59940,0x1009,0x1,{0},{0},{0},{0},NVT_STATUS_HDTV_1080P, "HDTV(analog):1080p"}}, {1280,0,400,80,1980,NVT_H_SYNC_NEGATIVE,720, 0, 5, 5,750, NVT_V_SYNC_NEGATIVE,NVT_PROGRESSIVE, 7425 , 74250, {0,50,50000,0x1009,0x1,{0},{0},{0},{0},NVT_STATUS_HDTV_720P50, "HDTV(analog):720p50"}}, {1920,0,594,88,2750,NVT_H_SYNC_NEGATIVE,1080,0, 4, 5,1125,NVT_V_SYNC_NEGATIVE,NVT_PROGRESSIVE, 7425 , 74250, {0,24,24000,0x1009,0x1,{0},{0},{0},{0},NVT_STATUS_HDTV_1080P24,"HDTV(analog):1080p24"}}, {1920,0,484,88,2640,NVT_H_SYNC_NEGATIVE,540, 0, 4, 5,562, NVT_V_SYNC_NEGATIVE,NVT_INTERLACED, 7425 , 74250, {0,50,50000,0x1009,0x1,{0},{0},{0},{0},NVT_STATUS_HDTV_1080I50,"HDTV(analog):1080i50"}}, {1920,0,484,88,2640,NVT_H_SYNC_NEGATIVE,1080,0, 4, 5,1125,NVT_V_SYNC_NEGATIVE,NVT_PROGRESSIVE,14850 ,148500, {0,50,50000,0x1009,0x1,{0},{0},{0},{0},NVT_STATUS_HDTV_1080P50,"HDTV(analog):1080p50"}}, {0,0,0,0,0,NVT_H_SYNC_NEGATIVE,0,0,0,0,0,NVT_V_SYNC_NEGATIVE,NVT_PROGRESSIVE,0,0,{0,0,0,0,0,{0},{0},{0},{0},0,""}} }; //*********************************************** //** Wrapper Structure to store Fake EDID data ** //*********************************************** typedef struct tagFAKE_TV_EDID { NvU32 EdidType; NvU32 EdidSize; const NvU8* FakeEdid; } FAKE_TV_EDID; // calculate the backend TV timing CODE_SEGMENT(PAGE_DD_CODE) NVT_STATUS NvTiming_GetTvTiming(NvU32 width, NvU32 height, NvU32 rr, NvU32 flag, NvU32 tvFormat, NVT_TIMING *pT) { NvU32 i, j, k; // input check if (pT == NULL) return NVT_STATUS_ERR; if ((width == 0 || height == 0 || rr == 0) && tvFormat >= NVT_MAX_TV_FORMAT) return NVT_STATUS_ERR; // handle double scan if (height <= NVT_PVT_DOUBLE_SCAN_HEIGHT) { width <<= 1; height <<= 1; } // try the exact match first if (tvFormat != NVT_AUTO_HDTV_FORMAT) { i = 0; while (TV_TIMING[i].HVisible != 0) { if (NVT_GET_TIMING_STATUS_SEQ(TV_TIMING[i].etc.status) == tvFormat) { // find the match *pT = TV_TIMING[i]; return NVT_STATUS_SUCCESS; } // move to the next entry i++; } // unknown TV format, return failure here *pT = TV_TIMING[0]; return NVT_STATUS_ERR; } // we are doing auto HDTV format binding here i = 0; j = k = sizeof(TV_TIMING)/sizeof(TV_TIMING[0]) - 1; while (TV_TIMING[i].HVisible != 0) { // #1: try the exact resolution/refreshrate/interlaced match if (width == TV_TIMING[i].HVisible && height == frame_height(TV_TIMING[i])&& rr == TV_TIMING[i].etc.rr && !!(flag & NVT_PVT_INTERLACED_MASK) == !!TV_TIMING[i].interlaced && NVT_GET_TIMING_STATUS_TYPE(TV_TIMING[i].etc.status) == NVT_TYPE_HDTV) { // exact match, return from here *pT = TV_TIMING[i]; return NVT_STATUS_SUCCESS; } // #2: try to closest match with interlaced check ON if (!!(flag & NVT_PVT_INTERLACED_MASK) == !!TV_TIMING[i].interlaced && NVT_GET_TIMING_STATUS_TYPE(TV_TIMING[i].etc.status) == NVT_TYPE_HDTV) { if (abs_delta(width, TV_TIMING[i].HVisible) <= abs_delta(width, TV_TIMING[j].HVisible) && abs_delta(height, frame_height(TV_TIMING[i])) <= abs_delta(height, frame_height(TV_TIMING[j])) && abs_delta(rr, TV_TIMING[i].etc.rr) <= abs_delta(rr, TV_TIMING[j].etc.rr) && width <= TV_TIMING[i].HVisible && height <= frame_height(TV_TIMING[i])) { j = i; } } // #3: try to closest match with interlaced check OFF if (NVT_GET_TIMING_STATUS_TYPE(TV_TIMING[i].etc.status) == NVT_TYPE_HDTV) { if (abs_delta(width, TV_TIMING[i].HVisible) <= abs_delta(width, TV_TIMING[k].HVisible) && abs_delta(height, frame_height(TV_TIMING[i])) <= abs_delta(height, frame_height(TV_TIMING[k])) && abs_delta(rr, TV_TIMING[i].etc.rr) <= abs_delta(rr, TV_TIMING[j].etc.rr) && width <= TV_TIMING[i].HVisible && height <= frame_height(TV_TIMING[i])) { k = i; } } // move to the next entry i++; } // return the closest matched timing here if (TV_TIMING[j].HVisible != 0) { *pT = TV_TIMING[j]; } else if (TV_TIMING[k].HVisible != 0) { *pT = TV_TIMING[k]; } else { *pT = TV_TIMING[0]; } // set the mismatch status if (pT->HVisible != width || frame_height(*pT) != height) { NVT_SET_TIMING_STATUS_MISMATCH(pT->etc.status, NVT_STATUS_TIMING_MISMATCH_SIZE); } if (pT->etc.rr != rr) { NVT_SET_TIMING_STATUS_MISMATCH(pT->etc.status, NVT_STATUS_TIMING_MISMATCH_RR); } if (!!pT->interlaced != !!(flag & NVT_PVT_INTERLACED_MASK)) { NVT_SET_TIMING_STATUS_MISMATCH(pT->etc.status, NVT_STATUS_TIMING_MISMATCH_FORMAT); } return NVT_STATUS_SUCCESS; } POP_SEGMENTS