mirror of
https://github.com/NVIDIA/open-gpu-kernel-modules.git
synced 2026-02-03 23:09:23 +00:00
2013 lines
80 KiB
C
2013 lines
80 KiB
C
//*****************************************************************************
|
|
//
|
|
// SPDX-FileCopyrightText: Copyright (c) 2024 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_displayid20.c
|
|
//
|
|
// Purpose: the provide displayID 2.0 related services
|
|
//
|
|
//*****************************************************************************
|
|
|
|
#include "nvBinSegment.h"
|
|
#include "nvmisc.h"
|
|
|
|
#include "nvtiming_pvt.h"
|
|
#include "displayid20.h"
|
|
|
|
PUSH_SEGMENTS
|
|
|
|
// Helper function
|
|
static NVT_STATUS getPrimaryUseCase(NvU8 product_type, NVT_DISPLAYID_PRODUCT_PRIMARY_USE_CASE *primary_use_case);
|
|
static NvU32 greatestCommonDenominator(NvU32 x, NvU32 y);
|
|
static NvU8 getExistedTimingSeqNumber(NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo, enum NVT_TIMING_TYPE);
|
|
|
|
/*
|
|
* The Second-generation version of VESA DisplayID Standard
|
|
* DisplayID v2.0
|
|
*
|
|
* @brief Parses a displayID20 section
|
|
*
|
|
* @param pDisplayId The DisplayId20 Section Block ()
|
|
* @param length Size of the displayId section Block
|
|
* @param pDisplayIdInfo Need to parse the raw data to store as NV structure
|
|
*
|
|
*/
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS NV_STDCALL
|
|
NvTiming_parseDisplayId20Info(
|
|
const NvU8 *pDisplayId,
|
|
NvU32 length,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
const DISPLAYID_2_0_SECTION *pSection = NULL;
|
|
NvU32 offset = 0;
|
|
NvU32 extensionIndex = 0;
|
|
NvU32 idx = 0;
|
|
|
|
// parameter check
|
|
if ((pDisplayId == NULL) ||
|
|
(pDisplayIdInfo == NULL))
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
pSection = (const DISPLAYID_2_0_SECTION *)pDisplayId;
|
|
|
|
if ((pSection->header.version < DISPLAYID_2_0_VERSION) ||
|
|
(DISPLAYID_2_0_SECTION_SIZE_TOTAL(pSection->header) > length))
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
NVMISC_MEMSET(pDisplayIdInfo, 0, sizeof(NVT_DISPLAYID_2_0_INFO));
|
|
|
|
status = parseDisplayId20BaseSection(pSection, pDisplayIdInfo);
|
|
if (status != NVT_STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
pDisplayIdInfo->extension_count = pSection->header.extension_count;
|
|
for (extensionIndex = 0; extensionIndex < pDisplayIdInfo->extension_count; extensionIndex++)
|
|
{
|
|
// Get offset to the next section.
|
|
offset += DISPLAYID_2_0_SECTION_SIZE_TOTAL(pSection->header);
|
|
|
|
// validate the next section buffer is valid
|
|
pSection = (const DISPLAYID_2_0_SECTION *)(pDisplayId + offset);
|
|
if ((offset + DISPLAYID_2_0_SECTION_SIZE_TOTAL(pSection->header)) > length)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
// process the section
|
|
status = parseDisplayId20ExtensionSection(pSection, pDisplayIdInfo);
|
|
if (status != NVT_STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
}
|
|
|
|
for (idx = 0; idx < pDisplayIdInfo->total_timings; idx++)
|
|
{
|
|
updateColorFormatForDisplayId20Timings(pDisplayIdInfo, idx);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NvU32
|
|
NvTiming_DisplayID2ValidationMask(
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayId20Info,
|
|
NvBool bIsStrongValidation)
|
|
{
|
|
NvU32 j;
|
|
NvU32 ret = 0;
|
|
|
|
// check the DisplayId2 version and signature
|
|
if (pDisplayId20Info->version != 0x2)
|
|
{
|
|
ret |= NVT_DID2_VALIDATION_ERR_MASK(NVT_DID2_VALIDATION_ERR_VERSION);
|
|
}
|
|
|
|
if (!pDisplayId20Info->valid_data_blocks.product_id_present)
|
|
{
|
|
ret |= NVT_DID2_VALIDATION_ERR_MASK(NVT_DID2_VALIDATION_ERR_PRODUCT_IDENTIFY);
|
|
}
|
|
|
|
if (pDisplayId20Info->primary_use_case >= PRODUCT_PRIMARY_USE_GENERIC_DISPLAY &&
|
|
pDisplayId20Info->primary_use_case <= PRODUCT_PRIMARY_USE_HEAD_MOUNT_AUGMENTED_REALITY)
|
|
{
|
|
if (!(pDisplayId20Info->valid_data_blocks.parameters_present &&
|
|
pDisplayId20Info->valid_data_blocks.interface_feature_present &&
|
|
pDisplayId20Info->valid_data_blocks.type7Timing_present &&
|
|
pDisplayId20Info->total_timings))
|
|
{
|
|
ret |= NVT_DID2_VALIDATION_ERR_MASK(NVT_DID2_VALIDATION_ERR_NO_DATA_BLOCK);
|
|
}
|
|
}
|
|
|
|
// Strong validation to follow
|
|
if (bIsStrongValidation == NV_TRUE)
|
|
{
|
|
// TODO : For each of the Data Block limitation
|
|
// Type 7 Timings data block
|
|
for (j = 0; j <= pDisplayId20Info->total_timings; j++)
|
|
{
|
|
if ( NVT_PREFERRED_TIMING_IS_DISPLAYID(pDisplayId20Info->timing[j].etc.flag) &&
|
|
(pDisplayId20Info->display_param.h_pixels != 0) &&
|
|
(pDisplayId20Info->display_param.v_pixels != 0))
|
|
{
|
|
if ( pDisplayId20Info->timing[j].HVisible != pDisplayId20Info->display_param.h_pixels ||
|
|
pDisplayId20Info->timing[j].VVisible != pDisplayId20Info->display_param.v_pixels )
|
|
{
|
|
ret |= NVT_DID2_VALIDATION_ERR_MASK(NVT_DID2_VALIDATION_ERR_NO_DATA_BLOCK);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// TODO : go on the next data block validation if it existed.
|
|
// TODO : validate extension blocks
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
NvTiming_DisplayID2ValidationDataBlocks(
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo,
|
|
NvBool bIsStrongValidation)
|
|
{
|
|
if (NvTiming_DisplayID2ValidationMask(pDisplayIdInfo, bIsStrongValidation) != 0)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
else
|
|
{
|
|
return NVT_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
// DisplayID20 Entry point functions
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20BaseSection(
|
|
const DISPLAYID_2_0_SECTION *pSection,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
|
|
// validate for section checksum before processing the data block
|
|
if (computeDisplayId20SectionCheckSum((const NvU8 *)pSection, DISPLAYID_2_0_SECTION_SIZE_TOTAL(pSection->header)) != 0)
|
|
{
|
|
status |= NVT_DID2_VALIDATION_ERR_MASK(NVT_DID2_VALIDATION_ERR_CHECKSUM);
|
|
return status;
|
|
}
|
|
|
|
pDisplayIdInfo->revision = pSection->header.revision;
|
|
pDisplayIdInfo->version = pSection->header.version;
|
|
|
|
status = getPrimaryUseCase(pSection->header.product_type,
|
|
&pDisplayIdInfo->primary_use_case);
|
|
if (status != NVT_STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
status = parseDisplayId20SectionDataBlocks(pSection, pDisplayIdInfo);
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20ExtensionSection(
|
|
const DISPLAYID_2_0_SECTION *pSection,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
|
|
// validate for section checksum before processing the data block
|
|
if (computeDisplayId20SectionCheckSum((const NvU8 *)pSection, DISPLAYID_2_0_SECTION_SIZE_TOTAL(pSection->header)) != 0)
|
|
{
|
|
status |= NVT_DID2_VALIDATION_ERR_MASK(NVT_DID2_VALIDATION_ERR_CHECKSUM);
|
|
return status;
|
|
}
|
|
|
|
nvt_assert(pSection->header.version >= DISPLAYID_2_0_VERSION);
|
|
nvt_assert(pSection->header.extension_count == 0);
|
|
nvt_assert(pSection->header.product_type == DISPLAYID_2_0_PROD_EXTENSION);
|
|
|
|
status = parseDisplayId20SectionDataBlocks(pSection, pDisplayIdInfo);
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20SectionDataBlocks(
|
|
const DISPLAYID_2_0_SECTION *pSection,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NvU32 i = 0;
|
|
NvU32 offset = 0;
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock = NULL;
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
|
|
while (offset < pSection->header.section_bytes)
|
|
{
|
|
// Get current block
|
|
pDataBlock = (const DISPLAYID_2_0_DATA_BLOCK_HEADER *)(pSection->data + offset);
|
|
|
|
// detected zero padding
|
|
if (pDataBlock->type == 0)
|
|
{
|
|
for (i = offset; i < pSection->header.section_bytes; i++)
|
|
{
|
|
// validate that all paddings are zeros
|
|
nvt_assert(pSection->data[i] == 0);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// check data block is valid.
|
|
if ((offset + DISPLAYID_2_0_DATA_BLOCK_SIZE_TOTAL(pDataBlock)) > pSection->header.section_bytes)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
// parse the data block
|
|
status = parseDisplayId20DataBlock(pDataBlock, pDisplayIdInfo);
|
|
if (status != NVT_STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
switch (pDataBlock->type)
|
|
{
|
|
case DISPLAYID_2_0_BLOCK_TYPE_PRODUCT_IDENTITY:
|
|
pDisplayIdInfo->valid_data_blocks.product_id_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_DISPLAY_PARAM:
|
|
pDisplayIdInfo->valid_data_blocks.parameters_present = NV_TRUE;
|
|
if (pDisplayIdInfo->display_param.audio_speakers_integrated == AUDIO_SPEAKER_INTEGRATED_SUPPORTED)
|
|
{
|
|
pDisplayIdInfo->basic_caps |= NVT_DISPLAY_2_0_CAP_BASIC_AUDIO;
|
|
}
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_TIMING_7:
|
|
pDisplayIdInfo->valid_data_blocks.type7Timing_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_TIMING_8:
|
|
pDisplayIdInfo->valid_data_blocks.type8Timing_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_TIMING_9:
|
|
pDisplayIdInfo->valid_data_blocks.type9Timing_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_RANGE_LIMITS:
|
|
pDisplayIdInfo->valid_data_blocks.dynamic_range_limit_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_INTERFACE_FEATURES:
|
|
pDisplayIdInfo->valid_data_blocks.interface_feature_present = NV_TRUE;
|
|
|
|
// Supported - Color depth is supported for all supported timings. Supported timing includes all Display-ID exposed timings
|
|
// (that is timing exposed using DisplayID timing types and CTA VICs)
|
|
if (IS_BPC_SUPPORTED_COLORFORMAT(pDisplayIdInfo->interface_features.yuv444.bpcs))
|
|
{
|
|
pDisplayIdInfo->basic_caps |= NVT_DISPLAY_2_0_CAP_YCbCr_444;
|
|
}
|
|
|
|
if (IS_BPC_SUPPORTED_COLORFORMAT(pDisplayIdInfo->interface_features.yuv422.bpcs))
|
|
{
|
|
pDisplayIdInfo->basic_caps |= NVT_DISPLAY_2_0_CAP_YCbCr_422;
|
|
}
|
|
|
|
if (pDisplayIdInfo->interface_features.audio_capability.support_48khz ||
|
|
pDisplayIdInfo->interface_features.audio_capability.support_44_1khz ||
|
|
pDisplayIdInfo->interface_features.audio_capability.support_32khz)
|
|
{
|
|
pDisplayIdInfo->basic_caps |= NVT_DISPLAY_2_0_CAP_BASIC_AUDIO;
|
|
}
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_STEREO:
|
|
pDisplayIdInfo->valid_data_blocks.stereo_interface_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_TILED_DISPLAY:
|
|
pDisplayIdInfo->valid_data_blocks.tiled_display_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_CONTAINER_ID:
|
|
pDisplayIdInfo->valid_data_blocks.container_id_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_TIMING_10:
|
|
pDisplayIdInfo->valid_data_blocks.type10Timing_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_ADAPTIVE_SYNC:
|
|
pDisplayIdInfo->valid_data_blocks.adaptive_sync_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_ARVR_HMD:
|
|
pDisplayIdInfo->valid_data_blocks.arvr_hmd_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_ARVR_LAYER:
|
|
pDisplayIdInfo->valid_data_blocks.arvr_layer_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_BRIGHTNESS_LUMINANCE_RANGE:
|
|
pDisplayIdInfo->valid_data_blocks.brightness_luminance_range_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_VENDOR_SPEC:
|
|
pDisplayIdInfo->valid_data_blocks.vendor_specific_present = NV_TRUE;
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_CTA_DATA:
|
|
pDisplayIdInfo->valid_data_blocks.cta_data_present = NV_TRUE;
|
|
break;
|
|
default:
|
|
status = NVT_STATUS_ERR;
|
|
}
|
|
|
|
// advance to the next block
|
|
offset += DISPLAYID_2_0_DATA_BLOCK_SIZE_TOTAL(pDataBlock);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20DataBlock(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
|
|
switch (pDataBlock->type)
|
|
{
|
|
case DISPLAYID_2_0_BLOCK_TYPE_PRODUCT_IDENTITY:
|
|
status = parseDisplayId20ProductIdentity(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_DISPLAY_PARAM:
|
|
status = parseDisplayId20DisplayParam(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_TIMING_7:
|
|
status = parseDisplayId20Timing7(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_TIMING_8:
|
|
status = parseDisplayId20Timing8(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_TIMING_9:
|
|
status = parseDisplayId20Timing9(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_TIMING_10:
|
|
status = parseDisplayId20Timing10(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_RANGE_LIMITS:
|
|
status = parseDisplayId20RangeLimit(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_INTERFACE_FEATURES:
|
|
status = parseDisplayId20DisplayInterfaceFeatures(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_STEREO:
|
|
status = parseDisplayId20Stereo(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_TILED_DISPLAY:
|
|
status = parseDisplayId20TiledDisplay(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_CONTAINER_ID:
|
|
status = parseDisplayId20ContainerId(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_ADAPTIVE_SYNC:
|
|
status = parseDisplayId20AdaptiveSync(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_ARVR_HMD:
|
|
status = parseDisplayId20ARVRHMD(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_ARVR_LAYER:
|
|
status = parseDisplayId20ARVRLayer(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_BRIGHTNESS_LUMINANCE_RANGE:
|
|
status = parseDisplayId20BrightnessLuminanceRange(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_VENDOR_SPEC:
|
|
status = parseDisplayId20VendorSpecific(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
case DISPLAYID_2_0_BLOCK_TYPE_CTA_DATA:
|
|
status = parseDisplayId20CtaData(pDataBlock, pDisplayIdInfo);
|
|
break;
|
|
default:
|
|
status = NVT_STATUS_ERR;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
// All Data Blocks Parsing
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20ProductIdentity(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
NVT_DISPLAYID_PRODUCT_IDENTITY *pProductIdentity = NULL;
|
|
const DISPLAYID_2_0_PROD_IDENTIFICATION_BLOCK *pProductIdBlock = NULL;
|
|
|
|
pProductIdBlock = (const DISPLAYID_2_0_PROD_IDENTIFICATION_BLOCK *)pDataBlock;
|
|
|
|
// add more validation if needed
|
|
|
|
if (pDisplayIdInfo == NULL) return status;
|
|
|
|
pProductIdentity = &pDisplayIdInfo->product_identity;
|
|
|
|
pProductIdentity->vendor_id = (pProductIdBlock->vendor[0] << 16) |
|
|
(pProductIdBlock->vendor[1] << 8) |
|
|
(pProductIdBlock->vendor[2]);
|
|
pProductIdentity->product_id = (pProductIdBlock->product_code[0]) |
|
|
(pProductIdBlock->product_code[1] << 8);
|
|
pProductIdentity->serial_number = (pProductIdBlock->serial_number[0]) |
|
|
(pProductIdBlock->serial_number[1] << 8) |
|
|
(pProductIdBlock->serial_number[2] << 16) |
|
|
(pProductIdBlock->serial_number[3] << 24);
|
|
pProductIdentity->week = (pProductIdBlock->model_tag >= 1 && pProductIdBlock->model_tag <= 52) ?
|
|
pProductIdBlock->model_tag : 0;
|
|
pProductIdentity->year = (pProductIdBlock->model_tag == 0xFF) ?
|
|
pProductIdBlock->model_year :
|
|
pProductIdBlock->model_year + 2000;
|
|
|
|
if (pProductIdBlock->product_name_string_size != 0)
|
|
{
|
|
NVMISC_STRNCPY((char *)pProductIdentity->product_string,
|
|
(const char *)pProductIdBlock->product_name_string,
|
|
pProductIdBlock->product_name_string_size);
|
|
}
|
|
pProductIdentity->product_string[pProductIdBlock->product_name_string_size] = '\0';
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20DisplayParam(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
const DISPLAYID_2_0_DISPLAY_PARAM_BLOCK *pDisplayParamBlock = NULL;
|
|
NVT_DISPLAYID_DISPLAY_PARAMETERS *pDisplayParam = NULL;
|
|
|
|
if (pDataBlock->data_bytes != DISPLAYID_2_0_DISPLAY_PARAM_BLOCK_PAYLOAD_LENGTH)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
// Add more validation here if needed
|
|
|
|
if (pDisplayIdInfo == NULL) return status;
|
|
|
|
pDisplayParamBlock = (const DISPLAYID_2_0_DISPLAY_PARAM_BLOCK *)pDataBlock;
|
|
pDisplayParam = &pDisplayIdInfo->display_param;
|
|
|
|
pDisplayParam->revision = pDisplayParamBlock->header.revision;
|
|
pDisplayParam->h_image_size_micro_meter = (pDisplayParamBlock->horizontal_image_size[1] << 8 |
|
|
pDisplayParamBlock->horizontal_image_size[0]) *
|
|
(pDisplayParamBlock->header.image_size_multiplier ? 1000 : 100);
|
|
pDisplayParam->v_image_size_micro_meter = (pDisplayParamBlock->vertical_image_size[1] << 8 |
|
|
pDisplayParamBlock->vertical_image_size[0]) *
|
|
(pDisplayParamBlock->header.image_size_multiplier ? 1000 : 100);
|
|
pDisplayParam->h_pixels = pDisplayParamBlock->horizontal_pixel_count[1] << 8 |
|
|
pDisplayParamBlock->horizontal_pixel_count[0];
|
|
pDisplayParam->v_pixels = pDisplayParamBlock->vertical_pixel_count[1] << 8 |
|
|
pDisplayParamBlock->vertical_pixel_count[0];
|
|
|
|
pDisplayParam->scan_orientation = pDisplayParamBlock->feature.scan_orientation;
|
|
pDisplayParam->audio_speakers_integrated = pDisplayParamBlock->feature.audio_speaker_information ? AUDIO_SPEAKER_INTEGRATED_NOT_SUPPORTED : AUDIO_SPEAKER_INTEGRATED_SUPPORTED;
|
|
pDisplayParam->color_map_standard = pDisplayParamBlock->feature.color_information ? COLOR_MAP_CIE_1976 : COLOR_MAP_CIE_1931;
|
|
|
|
// 12 bits Binary Fraction Representations
|
|
pDisplayParam->primaries[0].x = pDisplayParamBlock->primary_color_1_chromaticity.color_bits_mid.color_x_bits_high << 8 |
|
|
pDisplayParamBlock->primary_color_1_chromaticity.color_x_bits_low;
|
|
pDisplayParam->primaries[0].y = pDisplayParamBlock->primary_color_1_chromaticity.color_y_bits_high << 4 |
|
|
pDisplayParamBlock->primary_color_1_chromaticity.color_bits_mid.color_y_bits_low;
|
|
pDisplayParam->primaries[1].x = pDisplayParamBlock->primary_color_2_chromaticity.color_bits_mid.color_x_bits_high << 8 |
|
|
pDisplayParamBlock->primary_color_2_chromaticity.color_x_bits_low;
|
|
pDisplayParam->primaries[1].y = pDisplayParamBlock->primary_color_2_chromaticity.color_y_bits_high << 4 |
|
|
pDisplayParamBlock->primary_color_2_chromaticity.color_bits_mid.color_y_bits_low;
|
|
pDisplayParam->primaries[2].x = pDisplayParamBlock->primary_color_3_chromaticity.color_bits_mid.color_x_bits_high << 8 |
|
|
pDisplayParamBlock->primary_color_3_chromaticity.color_x_bits_low;
|
|
pDisplayParam->primaries[2].y = pDisplayParamBlock->primary_color_3_chromaticity.color_y_bits_high << 4 |
|
|
pDisplayParamBlock->primary_color_3_chromaticity.color_bits_mid.color_y_bits_low;
|
|
pDisplayParam->white.x = pDisplayParamBlock->white_point_chromaticity.color_bits_mid.color_x_bits_high << 8 |
|
|
pDisplayParamBlock->white_point_chromaticity.color_x_bits_low;
|
|
pDisplayParam->white.y = pDisplayParamBlock->white_point_chromaticity.color_y_bits_high << 4 |
|
|
pDisplayParamBlock->white_point_chromaticity.color_bits_mid.color_y_bits_low;
|
|
|
|
// IEEE 754 half-precision binary floating-point format
|
|
pDisplayParam->native_max_luminance_full_coverage = pDisplayParamBlock->max_luminance_full_coverage[1] << 8 |
|
|
pDisplayParamBlock->max_luminance_full_coverage[0];
|
|
pDisplayParam->native_max_luminance_10_percent_rect_coverage = pDisplayParamBlock->max_luminance_10_percent_rectangular_coverage[1] << 8 |
|
|
pDisplayParamBlock->max_luminance_10_percent_rectangular_coverage[0];
|
|
pDisplayParam->native_min_luminance = pDisplayParamBlock->min_luminance[1] << 8 |
|
|
pDisplayParamBlock->min_luminance[0];
|
|
|
|
if (pDisplayParamBlock->feature.luminance_information == 0)
|
|
{
|
|
pDisplayParam->native_luminance_info = NATIVE_LUMINANCE_INFO_MIN_GURANTEE_VALUE;
|
|
}
|
|
else if (pDisplayParamBlock->feature.luminance_information == 1)
|
|
{
|
|
pDisplayParam->native_luminance_info = NATIVE_LUMINANCE_INFO_SOURCE_DEVICE_GUIDANCE;
|
|
}
|
|
else
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
UPDATE_BPC_FOR_COLORFORMAT(pDisplayParam->native_color_depth,
|
|
pDisplayParamBlock->color_depth_and_device_technology.color_depth == NATIVE_COLOR_BPC_6,
|
|
pDisplayParamBlock->color_depth_and_device_technology.color_depth == NATIVE_COLOR_BPC_8,
|
|
pDisplayParamBlock->color_depth_and_device_technology.color_depth == NATIVE_COLOR_BPC_10,
|
|
pDisplayParamBlock->color_depth_and_device_technology.color_depth == NATIVE_COLOR_BPC_12,
|
|
0,
|
|
pDisplayParamBlock->color_depth_and_device_technology.color_depth == NATIVE_COLOR_BPC_16);
|
|
|
|
pDisplayParam->device_technology = pDisplayParamBlock->color_depth_and_device_technology.device_technology;
|
|
if (pDisplayParam->revision == 1)
|
|
{
|
|
pDisplayParam->device_theme_Preference = pDisplayParamBlock->color_depth_and_device_technology.device_theme_preference;
|
|
}
|
|
pDisplayParam->gamma_x100 = (pDisplayParamBlock->gamma_EOTF + 100);
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20Timing7(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
const DISPLAYID_2_0_TIMING_7_BLOCK *pTiming7Block = NULL;
|
|
NvU32 descriptorCount = 0;
|
|
NvU8 revision = 0;
|
|
NvU8 i = 0;
|
|
NvU8 startSeqNumber = 0;
|
|
|
|
NVT_TIMING newTiming;
|
|
|
|
pTiming7Block = (const DISPLAYID_2_0_TIMING_7_BLOCK *)pDataBlock;
|
|
|
|
// Based on the DisplayID_2_0_E7 spec:
|
|
// the Future descriptor can be defined with more than 20 Byte per descriptor without creating a new timing type
|
|
if (pTiming7Block->header.payload_bytes_len == 0)
|
|
{
|
|
if (pDataBlock->data_bytes % sizeof(DISPLAYID_2_0_TIMING_7_DESCRIPTOR) != 0)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
revision = pTiming7Block->header.revision;
|
|
descriptorCount = pDataBlock->data_bytes / (sizeof(DISPLAYID_2_0_TIMING_7_DESCRIPTOR) + pTiming7Block->header.payload_bytes_len);
|
|
|
|
if (descriptorCount < 1 || descriptorCount > DISPLAYID_2_0_TIMING_7_MAX_DESCRIPTORS)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
if (pDisplayIdInfo != NULL)
|
|
{
|
|
startSeqNumber = getExistedTimingSeqNumber(pDisplayIdInfo, NVT_TYPE_DISPLAYID_7);
|
|
}
|
|
|
|
for (i = 0; i < descriptorCount; i++)
|
|
{
|
|
NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
|
|
if (parseDisplayId20Timing7Descriptor(&pTiming7Block->descriptors[i], &newTiming, startSeqNumber+i) == NVT_STATUS_SUCCESS)
|
|
{
|
|
newTiming.etc.flag |= (revision >= DISPLAYID_2_0_TYPE7_DSC_PASSTHRU_REVISION && pTiming7Block->header.dsc_passthrough == 1) ?
|
|
NVT_FLAG_DISPLAYID_T7_DSC_PASSTHRU :
|
|
0;
|
|
|
|
if (revision >= DISPLAYID_2_0_TYPE7_YCC420_SUPPORT_REVISION)
|
|
{
|
|
newTiming.etc.flag |= pTiming7Block->descriptors[i].options.is_preferred_or_ycc420 ? NVT_FLAG_DISPLAYID_T7_T8_EXPLICT_YUV420 : 0;
|
|
|
|
if (pTiming7Block->descriptors[i].options.is_preferred_or_ycc420) // YCC 420 support
|
|
{
|
|
UPDATE_BPC_FOR_COLORFORMAT(newTiming.etc.yuv420, 0, 1, 1, 1, 0, 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
newTiming.etc.flag |= pTiming7Block->descriptors[i].options.is_preferred_or_ycc420 ? NVT_FLAG_DISPLAYID_DTD_PREFERRED_TIMING : 0;
|
|
}
|
|
|
|
NVT_SNPRINTF((char *)newTiming.etc.name, sizeof(newTiming.etc.name), "DID20-Type7:#%2d:%dx%dx%3d.%03dHz/%s",
|
|
(int)NVT_GET_TIMING_STATUS_SEQ(newTiming.etc.status),
|
|
(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.rep = 0x1;
|
|
|
|
if (!assignNextAvailableDisplayId20Timing(pDisplayIdInfo, &newTiming))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pDisplayIdInfo == NULL) return NVT_STATUS_ERR;
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20Timing8(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
const DISPLAYID_2_0_TIMING_8_BLOCK *pTiming8Block = NULL;
|
|
NVT_TIMING newTiming;
|
|
|
|
NvU8 codeCount = 0;
|
|
NvU8 startSeqNumber = 0;
|
|
NvU8 i;
|
|
|
|
pTiming8Block = (const DISPLAYID_2_0_TIMING_8_BLOCK *)pDataBlock;
|
|
codeCount = pDataBlock->data_bytes;
|
|
|
|
if (codeCount == 0)
|
|
{
|
|
nvt_assert(0 && "No available byte code!");
|
|
return NVT_STATUS_SUCCESS;
|
|
}
|
|
|
|
if (codeCount > DISPLAYID_2_0_TIMING_8_MAX_CODES)
|
|
{
|
|
nvt_assert(0 && "one byte code is out of range!");
|
|
return NVT_STATUS_SUCCESS;
|
|
}
|
|
|
|
if (pDisplayIdInfo != NULL)
|
|
{
|
|
startSeqNumber = getExistedTimingSeqNumber(pDisplayIdInfo, NVT_TYPE_DISPLAYID_8);
|
|
}
|
|
|
|
for (i = 0; i < codeCount; i++)
|
|
{
|
|
NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
|
|
|
|
if (parseDisplayId20Timing8Descriptor(&pTiming8Block->timingCode, &newTiming,
|
|
pTiming8Block->header.timing_code_type,
|
|
pTiming8Block->header.timing_code_size, i, startSeqNumber+i) == NVT_STATUS_SUCCESS)
|
|
{
|
|
newTiming.etc.flag |= ((pTiming8Block->header.revision == 1) && pTiming8Block->header.is_support_yuv420) ?
|
|
NVT_FLAG_DISPLAYID_T7_T8_EXPLICT_YUV420 :
|
|
0;
|
|
|
|
NVT_SNPRINTF((char *)newTiming.etc.name, sizeof(newTiming.etc.name), "DID20-Type8:#%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.name[sizeof(newTiming.etc.name) - 1] = '\0';
|
|
newTiming.etc.rep = 0x1;
|
|
|
|
if (!assignNextAvailableDisplayId20Timing(pDisplayIdInfo, &newTiming))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20Timing9(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
const DISPLAYID_2_0_TIMING_9_BLOCK *pTiming9Block = NULL;
|
|
NVT_TIMING newTiming;
|
|
NvU32 descriptorCount = 0;
|
|
NvU8 startSeqNumber = 0;
|
|
NvU8 i = 0;
|
|
|
|
descriptorCount = pDataBlock->data_bytes / sizeof(DISPLAYID_2_0_TIMING_9_DESCRIPTOR);
|
|
if (descriptorCount < 1 || descriptorCount > DISPLAYID_2_0_TIMING_9_MAX_DESCRIPTORS)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
pTiming9Block = (const DISPLAYID_2_0_TIMING_9_BLOCK *)pDataBlock;
|
|
|
|
if (pDisplayIdInfo != NULL)
|
|
{
|
|
startSeqNumber = getExistedTimingSeqNumber(pDisplayIdInfo, NVT_TYPE_DISPLAYID_9);
|
|
}
|
|
|
|
for (i = 0; i < descriptorCount; i++)
|
|
{
|
|
NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
|
|
|
|
if (parseDisplayId20Timing9Descriptor(&pTiming9Block->descriptors[i], &newTiming, startSeqNumber+i) == NVT_STATUS_SUCCESS)
|
|
{
|
|
if (!assignNextAvailableDisplayId20Timing(pDisplayIdInfo, &newTiming))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pDisplayIdInfo == NULL) return NVT_STATUS_ERR;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20Timing10(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
NvU32 descriptorCount = 0;
|
|
NvU8 startSeqNumber = 0;
|
|
NvU8 i = 0;
|
|
NvU8 eachOfDescriptorsSize = sizeof(DISPLAYID_2_0_TIMING_10_6BYTES_DESCRIPTOR);
|
|
|
|
const DISPLAYID_2_0_TIMING_10_BLOCK *pTiming10Block = NULL;
|
|
const DISPLAYID_2_0_TIMING_10_6BYTES_DESCRIPTOR *p6bytesDescriptor = NULL;
|
|
|
|
NVT_TIMING newTiming;
|
|
|
|
pTiming10Block = (const DISPLAYID_2_0_TIMING_10_BLOCK *)pDataBlock;
|
|
|
|
if (pTiming10Block->header.type != DISPLAYID_2_0_BLOCK_TYPE_TIMING_10)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
if (pTiming10Block->header.payload_bytes_len == DISPLAYID_2_0_TIMING_10_PAYLOAD_BYTES_6)
|
|
{
|
|
descriptorCount = pDataBlock->data_bytes / sizeof(DISPLAYID_2_0_TIMING_10_6BYTES_DESCRIPTOR);
|
|
|
|
if (descriptorCount < 1 || descriptorCount > DISPLAYID_2_0_TIMING_10_MAX_6BYTES_DESCRIPTORS)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
}
|
|
else if (pTiming10Block->header.payload_bytes_len == DISPLAYID_2_0_TIMING_10_PAYLOAD_BYTES_7)
|
|
{
|
|
descriptorCount = pDataBlock->data_bytes / sizeof(DISPLAYID_2_0_TIMING_10_7BYTES_DESCRIPTOR);
|
|
|
|
if (descriptorCount < 1 || descriptorCount > DISPLAYID_2_0_TIMING_10_MAX_7BYTES_DESCRIPTORS)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
}
|
|
else if (pTiming10Block->header.payload_bytes_len == DISPLAYID_2_1_TIMING_10_PAYLOAD_BYTES_8)
|
|
{
|
|
descriptorCount = pDataBlock->data_bytes / sizeof(DISPLAYID_2_1_TIMING_10_8BYTES_DESCRIPTOR);
|
|
|
|
if (descriptorCount < 1 || descriptorCount > DISPLAYID_2_1_TIMING_10_MAX_8BYTES_DESCRIPTORS)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
}
|
|
|
|
eachOfDescriptorsSize += pTiming10Block->header.payload_bytes_len;
|
|
|
|
if (pDisplayIdInfo != NULL)
|
|
{
|
|
startSeqNumber = getExistedTimingSeqNumber(pDisplayIdInfo, NVT_TYPE_DISPLAYID_10);
|
|
}
|
|
|
|
for (i = 0; i < descriptorCount; i++)
|
|
{
|
|
NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
|
|
if (NVT_STATUS_SUCCESS == parseDisplayId20Timing10Descriptor(&pTiming10Block->descriptors[i*eachOfDescriptorsSize],
|
|
&newTiming,
|
|
pTiming10Block->header.payload_bytes_len,
|
|
startSeqNumber+i))
|
|
{
|
|
p6bytesDescriptor = (const DISPLAYID_2_0_TIMING_10_6BYTES_DESCRIPTOR *)&pTiming10Block->descriptors[i*eachOfDescriptorsSize];
|
|
|
|
if (p6bytesDescriptor->options.ycc420_support)
|
|
{
|
|
UPDATE_BPC_FOR_COLORFORMAT(newTiming.etc.yuv420, 0, 1, 1, 1, 0, 1);
|
|
}
|
|
|
|
if (p6bytesDescriptor->options.timing_formula == DISPLAYID_2_0_TIMING_FORMULA_CVT_1_2_STANDARD_CRT_BASED)
|
|
{
|
|
NVT_SNPRINTF((char *)newTiming.etc.name, sizeof(newTiming.etc.name), "DID20-Type10:#%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), "DID20-Type10RB%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.name[sizeof(newTiming.etc.name) - 1] = '\0';
|
|
newTiming.etc.rep = 0x1;
|
|
|
|
if (!assignNextAvailableDisplayId20Timing(pDisplayIdInfo, &newTiming))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pDisplayIdInfo == NULL)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20RangeLimit(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
const DISPLAYID_2_0_RANGE_LIMITS_BLOCK *pRangeLimitsBlock = NULL;
|
|
NVT_DISPLAYID_RANGE_LIMITS rangeLimits = {0};
|
|
|
|
// basic sanity check
|
|
if (pDataBlock->data_bytes != DISPLAYID_2_0_RANGE_LIMITS_BLOCK_PAYLOAD_LENGTH)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
pRangeLimitsBlock = (const DISPLAYID_2_0_RANGE_LIMITS_BLOCK *)pDataBlock;
|
|
|
|
rangeLimits.revision = pDataBlock->revision;
|
|
|
|
rangeLimits.pclk_min = (pRangeLimitsBlock->pixel_clock_min[2] << 16 |
|
|
pRangeLimitsBlock->pixel_clock_min[1] << 8 |
|
|
pRangeLimitsBlock->pixel_clock_min[0]) + 1;
|
|
rangeLimits.pclk_max = (pRangeLimitsBlock->pixel_clock_max[2] << 16 |
|
|
pRangeLimitsBlock->pixel_clock_max[1] << 8 |
|
|
pRangeLimitsBlock->pixel_clock_max[0]) + 1;
|
|
rangeLimits.vfreq_min = pRangeLimitsBlock->vertical_frequency_min;
|
|
if (rangeLimits.revision == 1)
|
|
{
|
|
rangeLimits.vfreq_max = pRangeLimitsBlock->dynamic_video_timing_range_support.vertical_frequency_max_9_8 << 8 |
|
|
pRangeLimitsBlock->vertical_frequency_max_7_0;
|
|
}
|
|
else
|
|
{
|
|
rangeLimits.vfreq_max = pRangeLimitsBlock->vertical_frequency_max_7_0;
|
|
}
|
|
|
|
rangeLimits.seamless_dynamic_video_timing_change = pRangeLimitsBlock->dynamic_video_timing_range_support.seamless_dynamic_video_timing_change;
|
|
|
|
if (pDisplayIdInfo == NULL)
|
|
{
|
|
if (rangeLimits.vfreq_min > rangeLimits.vfreq_max || rangeLimits.pclk_min > rangeLimits.pclk_max ||
|
|
rangeLimits.vfreq_min == 0 || rangeLimits.vfreq_max == 0)
|
|
{
|
|
nvt_assert(0 && "wrong range limit");
|
|
status = NVT_STATUS_ERR;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NVMISC_MEMCPY(&pDisplayIdInfo->range_limits, &rangeLimits, sizeof(NVT_DISPLAYID_RANGE_LIMITS));
|
|
|
|
return status;
|
|
}
|
|
|
|
#define ADD_COLOR_SPACE_EOTF_COMBINATION(_pInterfaceFeatures, _color_space, _eotf) do { \
|
|
(_pInterfaceFeatures)->colorspace_eotf_combination[(_pInterfaceFeatures)->combination_count].color_space = (_color_space); \
|
|
(_pInterfaceFeatures)->colorspace_eotf_combination[(_pInterfaceFeatures)->combination_count].eotf = (_eotf); \
|
|
(_pInterfaceFeatures)->combination_count++; \
|
|
} while(0)
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20DisplayInterfaceFeatures(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
NvU32 i = 0;
|
|
const DISPLAYID_2_0_INTERFACE_FEATURES_BLOCK *pInterfaceFeaturesBlock = NULL;
|
|
NVT_DISPLAYID_INTERFACE_FEATURES *pInterfaceFeatures = NULL;
|
|
|
|
if (pDataBlock->data_bytes < DISPLAYID_2_0_INTERFACE_FEATURES_BLOCK_PAYLOAD_LENGTH_MIN)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
// Add more validation here if needed.
|
|
|
|
if (pDisplayIdInfo == NULL) return status;
|
|
|
|
pInterfaceFeatures = &pDisplayIdInfo->interface_features;
|
|
|
|
pInterfaceFeaturesBlock = (const DISPLAYID_2_0_INTERFACE_FEATURES_BLOCK *)pDataBlock;
|
|
pInterfaceFeatures->revision = pDataBlock->revision;
|
|
|
|
UPDATE_BPC_FOR_COLORFORMAT(pInterfaceFeatures->rgb444,
|
|
pInterfaceFeaturesBlock->interface_color_depth_rgb.bit_per_primary_6,
|
|
pInterfaceFeaturesBlock->interface_color_depth_rgb.bit_per_primary_8,
|
|
pInterfaceFeaturesBlock->interface_color_depth_rgb.bit_per_primary_10,
|
|
pInterfaceFeaturesBlock->interface_color_depth_rgb.bit_per_primary_12,
|
|
pInterfaceFeaturesBlock->interface_color_depth_rgb.bit_per_primary_14,
|
|
pInterfaceFeaturesBlock->interface_color_depth_rgb.bit_per_primary_16);
|
|
UPDATE_BPC_FOR_COLORFORMAT(pInterfaceFeatures->yuv444,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr444.bit_per_primary_6,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr444.bit_per_primary_8,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr444.bit_per_primary_10,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr444.bit_per_primary_12,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr444.bit_per_primary_14,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr444.bit_per_primary_16);
|
|
UPDATE_BPC_FOR_COLORFORMAT(pInterfaceFeatures->yuv422,
|
|
0,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr422.bit_per_primary_8,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr422.bit_per_primary_10,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr422.bit_per_primary_12,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr422.bit_per_primary_14,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr422.bit_per_primary_16);
|
|
UPDATE_BPC_FOR_COLORFORMAT(pInterfaceFeatures->yuv420,
|
|
0,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr420.bit_per_primary_8,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr420.bit_per_primary_10,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr420.bit_per_primary_12,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr420.bit_per_primary_14,
|
|
pInterfaceFeaturesBlock->interface_color_depth_ycbcr420.bit_per_primary_16);
|
|
|
|
// * 74.25MP/s
|
|
pInterfaceFeatures->yuv420_min_pclk = pInterfaceFeaturesBlock->min_pixel_rate_ycbcr420 *
|
|
7425;
|
|
|
|
pInterfaceFeatures->audio_capability.support_48khz =
|
|
pInterfaceFeaturesBlock->audio_capability.sample_rate_48_khz;
|
|
pInterfaceFeatures->audio_capability.support_44_1khz =
|
|
pInterfaceFeaturesBlock->audio_capability.sample_rate_44_1_khz;
|
|
pInterfaceFeatures->audio_capability.support_32khz =
|
|
pInterfaceFeaturesBlock->audio_capability.sample_rate_32_khz;
|
|
|
|
if (pInterfaceFeaturesBlock->color_space_and_eotf_1.color_space_srgb_eotf_srgb)
|
|
{
|
|
ADD_COLOR_SPACE_EOTF_COMBINATION(pInterfaceFeatures,
|
|
INTERFACE_COLOR_SPACE_SRGB,
|
|
INTERFACE_EOTF_SRGB);
|
|
}
|
|
if (pInterfaceFeaturesBlock->color_space_and_eotf_1.color_space_bt601_eotf_bt601)
|
|
{
|
|
ADD_COLOR_SPACE_EOTF_COMBINATION(pInterfaceFeatures,
|
|
INTERFACE_COLOR_SPACE_BT601,
|
|
INTERFACE_EOTF_BT601);
|
|
}
|
|
if (pInterfaceFeaturesBlock->color_space_and_eotf_1.color_space_bt709_eotf_bt1886)
|
|
{
|
|
ADD_COLOR_SPACE_EOTF_COMBINATION(pInterfaceFeatures,
|
|
INTERFACE_COLOR_SPACE_BT709,
|
|
INTERFACE_EOTF_BT1886);
|
|
}
|
|
if (pInterfaceFeaturesBlock->color_space_and_eotf_1.color_space_adobe_rgb_eotf_adobe_rgb)
|
|
{
|
|
ADD_COLOR_SPACE_EOTF_COMBINATION(pInterfaceFeatures,
|
|
INTERFACE_COLOR_SPACE_ADOBE_RGB,
|
|
INTERFACE_EOTF_ADOBE_RGB);
|
|
}
|
|
if (pInterfaceFeaturesBlock->color_space_and_eotf_1.color_space_dci_p3_eotf_dci_p3)
|
|
{
|
|
ADD_COLOR_SPACE_EOTF_COMBINATION(pInterfaceFeatures,
|
|
INTERFACE_COLOR_SPACE_DCI_P3,
|
|
INTERFACE_EOTF_DCI_P3);
|
|
}
|
|
if (pInterfaceFeaturesBlock->color_space_and_eotf_1.color_space_bt2020_eotf_bt2020)
|
|
{
|
|
ADD_COLOR_SPACE_EOTF_COMBINATION(pInterfaceFeatures,
|
|
INTERFACE_COLOR_SPACE_BT2020,
|
|
INTERFACE_EOTF_BT2020);
|
|
}
|
|
if (pInterfaceFeaturesBlock->color_space_and_eotf_1.color_space_bt2020_eotf_smpte_st2084)
|
|
{
|
|
ADD_COLOR_SPACE_EOTF_COMBINATION(pInterfaceFeatures,
|
|
INTERFACE_COLOR_SPACE_BT2020,
|
|
INTERFACE_EOTF_SMPTE_ST2084);
|
|
}
|
|
|
|
for (i = 0; i < pInterfaceFeaturesBlock->additional_color_space_and_eotf_count.count; i++)
|
|
{
|
|
ADD_COLOR_SPACE_EOTF_COMBINATION(pInterfaceFeatures,
|
|
pInterfaceFeaturesBlock->additional_color_space_and_eotf[i].color_space,
|
|
pInterfaceFeaturesBlock->additional_color_space_and_eotf[i].eotf);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20Stereo(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
|
|
if (pDisplayIdInfo == NULL) return status;
|
|
|
|
// TODO: Implement the parsing here.
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20TiledDisplay(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
const DISPLAYID_2_0_TILED_DISPLAY_BLOCK *pTiledDisplayBlock = NULL;
|
|
NVT_DISPLAYID_TILED_DISPLAY_TOPOLOGY *pTileTopo = NULL;
|
|
|
|
if (pDataBlock->data_bytes != DISPLAYID_2_0_TILED_DISPLAY_BLOCK_PAYLOAD_LENGTH)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
if (pDisplayIdInfo == NULL) return status;
|
|
|
|
pTiledDisplayBlock = (const DISPLAYID_2_0_TILED_DISPLAY_BLOCK *)pDataBlock;
|
|
pTileTopo = &pDisplayIdInfo->tile_topo;
|
|
|
|
pTileTopo->revision = pDataBlock->revision;
|
|
|
|
pTileTopo->capability.bSingleEnclosure = pTiledDisplayBlock->capability.single_enclosure;
|
|
pTileTopo->capability.bHasBezelInfo = pTiledDisplayBlock->capability.has_bezel_info;
|
|
pTileTopo->capability.multi_tile_behavior = pTiledDisplayBlock->capability.multi_tile_behavior;
|
|
pTileTopo->capability.single_tile_behavior = pTiledDisplayBlock->capability.single_tile_behavior;
|
|
|
|
pTileTopo->topology.row = ((pTiledDisplayBlock->topo_loc_high.row << 5) |
|
|
(pTiledDisplayBlock->topo_low.row)) + 1;
|
|
pTileTopo->topology.col = ((pTiledDisplayBlock->topo_loc_high.col << 5) |
|
|
(pTiledDisplayBlock->topo_low.col)) + 1;
|
|
pTileTopo->location.x = ((pTiledDisplayBlock->topo_loc_high.x << 5) |
|
|
(pTiledDisplayBlock->loc_low.x));
|
|
pTileTopo->location.y = ((pTiledDisplayBlock->topo_loc_high.y << 5) |
|
|
(pTiledDisplayBlock->loc_low.y));
|
|
|
|
pTileTopo->native_resolution.width = ((pTiledDisplayBlock->native_resolution.width_high << 8) |
|
|
pTiledDisplayBlock->native_resolution.width_low) + 1;
|
|
pTileTopo->native_resolution.height = ((pTiledDisplayBlock->native_resolution.height_high << 8) |
|
|
pTiledDisplayBlock->native_resolution.height_low) + 1;
|
|
|
|
pTileTopo->bezel_info.top = (pTiledDisplayBlock->bezel_info.top *
|
|
pTiledDisplayBlock->bezel_info.pixel_density) / 10;
|
|
pTileTopo->bezel_info.bottom = (pTiledDisplayBlock->bezel_info.bottom *
|
|
pTiledDisplayBlock->bezel_info.pixel_density) / 10;
|
|
pTileTopo->bezel_info.right = (pTiledDisplayBlock->bezel_info.right *
|
|
pTiledDisplayBlock->bezel_info.pixel_density) / 10;
|
|
pTileTopo->bezel_info.left = (pTiledDisplayBlock->bezel_info.left *
|
|
pTiledDisplayBlock->bezel_info.pixel_density) / 10;
|
|
|
|
pTileTopo->tile_topology_id.vendor_id = pTiledDisplayBlock->topo_id.vendor_id[0] << 16 |
|
|
pTiledDisplayBlock->topo_id.vendor_id[1] << 8 |
|
|
pTiledDisplayBlock->topo_id.vendor_id[2];
|
|
pTileTopo->tile_topology_id.product_id = pTiledDisplayBlock->topo_id.product_id[1] << 8 |
|
|
pTiledDisplayBlock->topo_id.product_id[0];
|
|
pTileTopo->tile_topology_id.serial_number = pTiledDisplayBlock->topo_id.serial_number[3] << 24 |
|
|
pTiledDisplayBlock->topo_id.serial_number[2] << 16 |
|
|
pTiledDisplayBlock->topo_id.serial_number[1] << 8 |
|
|
pTiledDisplayBlock->topo_id.serial_number[0];
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20ContainerId(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
const DISPLAYID_2_0_CONTAINERID_BLOCK *pContainerIdBlock = NULL;
|
|
NVT_DISPLAYID_CONTAINERID *pContainerId = NULL;
|
|
|
|
if (pDataBlock->data_bytes != DISPLAYID_2_0_CONTAINERID_BLOCK_PAYLOAD_LENGTH)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
if (pDisplayIdInfo == NULL) return status;
|
|
|
|
pContainerIdBlock = (const DISPLAYID_2_0_CONTAINERID_BLOCK *)pDataBlock;
|
|
pContainerId = &pDisplayIdInfo->container_id;
|
|
|
|
pContainerId->revision = pDataBlock->revision;
|
|
pContainerId->data1 = pContainerIdBlock->container_id[0] << 24 |
|
|
pContainerIdBlock->container_id[1] << 16 |
|
|
pContainerIdBlock->container_id[2] << 8 |
|
|
pContainerIdBlock->container_id[3];
|
|
pContainerId->data2 = pContainerIdBlock->container_id[4] << 8 |
|
|
pContainerIdBlock->container_id[5];
|
|
pContainerId->data3 = pContainerIdBlock->container_id[6] << 8 |
|
|
pContainerIdBlock->container_id[7];
|
|
pContainerId->data4 = pContainerIdBlock->container_id[8] << 8 |
|
|
pContainerIdBlock->container_id[9];
|
|
pContainerId->data5[0] = pContainerIdBlock->container_id[10];
|
|
pContainerId->data5[1] = pContainerIdBlock->container_id[11];
|
|
pContainerId->data5[2] = pContainerIdBlock->container_id[12];
|
|
pContainerId->data5[3] = pContainerIdBlock->container_id[13];
|
|
pContainerId->data5[4] = pContainerIdBlock->container_id[14];
|
|
pContainerId->data5[5] = pContainerIdBlock->container_id[15];
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20AdaptiveSync(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
const DISPLAYID_2_0_ADAPTIVE_SYNC_BLOCK *pAdaptiveSyncBlock = NULL;
|
|
NvU32 descriptorCnt = 0;
|
|
NvU8 i = 0;
|
|
NvU8 minRR = 0;
|
|
NvU16 maxRR = 0;
|
|
|
|
pAdaptiveSyncBlock = (const DISPLAYID_2_0_ADAPTIVE_SYNC_BLOCK *)pDataBlock;
|
|
|
|
if (pAdaptiveSyncBlock->header.payload_bytes_adaptive_sync_len == 0)
|
|
{
|
|
// Sanity check
|
|
if (pDataBlock->data_bytes % sizeof(DISPLAYID_2_0_ADAPTIVE_SYNC_DESCRIPTOR) != 0)
|
|
{
|
|
status = NVT_STATUS_ERR;
|
|
}
|
|
|
|
descriptorCnt = pDataBlock->data_bytes / sizeof(DISPLAYID_2_0_ADAPTIVE_SYNC_DESCRIPTOR);
|
|
|
|
if (descriptorCnt < 1) return NVT_STATUS_ERR;
|
|
|
|
if (pDisplayIdInfo == NULL)
|
|
{
|
|
for (i = 0; i < descriptorCnt; i++)
|
|
{
|
|
minRR = pAdaptiveSyncBlock->descriptors[i].min_refresh_rate;
|
|
maxRR = (pAdaptiveSyncBlock->descriptors[i].max_refresh_rate.max_rr_9_8 << 8 |
|
|
pAdaptiveSyncBlock->descriptors[i].max_refresh_rate.max_rr_7_0) + 1;
|
|
if (minRR > (maxRR + 1) || minRR == 0 || maxRR == 0)
|
|
{
|
|
status = NVT_STATUS_ERR;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
pDisplayIdInfo->total_adaptive_sync_descriptor = descriptorCnt;
|
|
|
|
for (i = 0; i < descriptorCnt; i++)
|
|
{
|
|
// Byte 0 Adaptive-Sync Operation and Range Information
|
|
pDisplayIdInfo->adaptive_sync_descriptor[i].u.information.adaptive_sync_range = pAdaptiveSyncBlock->descriptors[i].operation_range_info.range;
|
|
pDisplayIdInfo->adaptive_sync_descriptor[i].u.information.duration_inc_flicker_perf = pAdaptiveSyncBlock->descriptors[i].operation_range_info.successive_frame_inc_tolerance;
|
|
pDisplayIdInfo->adaptive_sync_descriptor[i].u.information.modes = pAdaptiveSyncBlock->descriptors[i].operation_range_info.modes;
|
|
pDisplayIdInfo->adaptive_sync_descriptor[i].u.information.seamless_not_support = pAdaptiveSyncBlock->descriptors[i].operation_range_info.seamless_transition_not_support;
|
|
pDisplayIdInfo->adaptive_sync_descriptor[i].u.information.duration_dec_flicker_perf = pAdaptiveSyncBlock->descriptors[i].operation_range_info.successive_frame_dec_tolerance;
|
|
|
|
// 6.2 format (six integer bits and two fractional bits) a value range of 0.00 to 63.75ms
|
|
pDisplayIdInfo->adaptive_sync_descriptor[i].max_duration_inc = pAdaptiveSyncBlock->descriptors[i].max_single_frame_inc;
|
|
pDisplayIdInfo->adaptive_sync_descriptor[i].min_rr = pAdaptiveSyncBlock->descriptors[i].min_refresh_rate;
|
|
pDisplayIdInfo->adaptive_sync_descriptor[i].max_rr = (pAdaptiveSyncBlock->descriptors[i].max_refresh_rate.max_rr_9_8 << 8 |
|
|
pAdaptiveSyncBlock->descriptors[i].max_refresh_rate.max_rr_7_0) + 1;
|
|
// 6.2 format (six integer bits and two fractional bits) a value range of 0.00 to 63.75ms
|
|
pDisplayIdInfo->adaptive_sync_descriptor[i].max_duration_dec = pAdaptiveSyncBlock->descriptors[i].max_single_frame_dec;
|
|
}
|
|
}
|
|
else // all other values are RESERVED.
|
|
{
|
|
if (pDisplayIdInfo == NULL) return NVT_STATUS_ERR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20ARVRHMD(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
|
|
if (pDisplayIdInfo == NULL) return status;
|
|
|
|
// TODO: Implement the parsing here.
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20ARVRLayer(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
|
|
if (pDisplayIdInfo == NULL) return status;
|
|
|
|
// TODO: Implement the parsing here.
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20BrightnessLuminanceRange(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
const DISPLAYID_2_0_BRIGHTNESS_LUMINANCE_RANGE_BLOCK *pBrightnessLuminanceRangeBlock = NULL;
|
|
NVT_DISPLAYID_BRIGHTNESS_LUMINANCE_RANGE *pluminanceRanges = NULL;
|
|
|
|
if ((pDataBlock == NULL) || pDataBlock->data_bytes != DISPLAYID_2_0_BRIGHTNESS_LUMINANCE_RANGE_BLOCK_PAYLOAD_LENGTH)
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
if (pDisplayIdInfo == NULL) return status;
|
|
|
|
pBrightnessLuminanceRangeBlock = (const DISPLAYID_2_0_BRIGHTNESS_LUMINANCE_RANGE_BLOCK *)pDataBlock;
|
|
pluminanceRanges = &pDisplayIdInfo->luminance_ranges;
|
|
|
|
pluminanceRanges->revision = pDataBlock->revision;
|
|
pluminanceRanges->min_sdr_luminance = pBrightnessLuminanceRangeBlock->min_sdr_luminance;
|
|
pluminanceRanges->max_sdr_luminance = pBrightnessLuminanceRangeBlock->max_sdr_luminance;
|
|
pluminanceRanges->max_boost_sdr_luminance = pBrightnessLuminanceRangeBlock->max_boost_sdr_luminance;
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20VendorSpecific(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
const DISPLAYID_2_0_VENDOR_SPECIFIC_BLOCK *block = NULL;
|
|
NVT_DISPLAYID_VENDOR_SPECIFIC *pVendorSpecific = NULL;
|
|
NvU32 ieee_oui = 0;
|
|
|
|
// Add more validation here if needed
|
|
|
|
if (pDisplayIdInfo == NULL) return status;
|
|
|
|
block = (const DISPLAYID_2_0_VENDOR_SPECIFIC_BLOCK*)pDataBlock;
|
|
pVendorSpecific = &pDisplayIdInfo->vendor_specific;
|
|
|
|
ieee_oui = (NvU32)((block->vendor_id[0] << 16) |
|
|
(block->vendor_id[1] << 8) |
|
|
(block->vendor_id[2]));
|
|
|
|
switch (ieee_oui)
|
|
{
|
|
case NVT_VESA_VENDOR_SPECIFIC_IEEE_ID:
|
|
// TODO: below parser shall be updated if DID21 changed in the future
|
|
if (pDataBlock->data_bytes == NVT_VESA_VENDOR_SPECIFIC_LENGTH)
|
|
{
|
|
pVendorSpecific->vesaVsdb.data_struct_type.type =
|
|
block->vendor_specific_data[3] & NVT_VESA_ORG_VSDB_DATA_TYPE_MASK;
|
|
pVendorSpecific->vesaVsdb.data_struct_type.color_space_and_eotf =
|
|
(block->vendor_specific_data[3] & NVT_VESA_ORG_VSDB_COLOR_SPACE_AND_EOTF_MASK) >> NVT_VESA_ORG_VSDB_COLOR_SPACE_AND_EOTF_SHIFT;
|
|
pVendorSpecific->vesaVsdb.overlapping.pixels_overlapping_count =
|
|
block->vendor_specific_data[4] & NVT_VESA_ORG_VSDB_PIXELS_OVERLAPPING_MASK;
|
|
pVendorSpecific->vesaVsdb.overlapping.multi_sst =
|
|
(block->vendor_specific_data[4] & NVT_VESA_ORG_VSDB_MULTI_SST_MODE_MASK) >> NVT_VESA_ORG_VSDB_MULTI_SST_MODE_SHIFT;
|
|
pVendorSpecific->vesaVsdb.pass_through_integer.pass_through_integer_dsc =
|
|
block->vendor_specific_data[5] & NVT_VESA_ORG_VSDB_PASS_THROUGH_INTEGER_MASK;
|
|
pVendorSpecific->vesaVsdb.pass_through_fractional.pass_through_fraction_dsc =
|
|
block->vendor_specific_data[6] & NVT_VESA_ORG_VSDB_PASS_THROUGH_FRACTIOINAL_MASK;
|
|
}
|
|
else
|
|
{
|
|
status = NVT_STATUS_ERR;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20CtaData(
|
|
const DISPLAYID_2_0_DATA_BLOCK_HEADER *pDataBlock,
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
|
|
NVT_EDID_CEA861_INFO *p861Info = NULL;
|
|
const DISPLAYID_2_0_CTA_BLOCK * ctaBlock = NULL;
|
|
NvU8 *pcta_data = NULL;
|
|
|
|
ctaBlock = (const DISPLAYID_2_0_CTA_BLOCK *)pDataBlock;
|
|
|
|
// WAR here to add a (size_t) cast for casting member from const to non-const in order to avoid Linux old compiler failed in DVS.
|
|
pcta_data = (NvU8 *)(size_t)ctaBlock->cta_data;
|
|
|
|
if (pDisplayIdInfo == NULL)
|
|
{
|
|
status = parseCta861DataBlockInfo(pcta_data, pDataBlock->data_bytes, NULL);
|
|
return status;
|
|
}
|
|
else
|
|
{
|
|
status = parseCta861DataBlockInfo(pcta_data, pDataBlock->data_bytes, &pDisplayIdInfo->cta.cta861_info);
|
|
}
|
|
|
|
if (status != NVT_STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
p861Info = &(pDisplayIdInfo->cta.cta861_info);
|
|
|
|
parseCta861VsdbBlocks(p861Info, pDisplayIdInfo, FROM_DISPLAYID_20_DATA_BLOCK);
|
|
parseCta861VsvdbBlocks(p861Info, pDisplayIdInfo, FROM_DISPLAYID_20_DATA_BLOCK);
|
|
|
|
parseCta861HfScdb(p861Info, pDisplayIdInfo, FROM_DISPLAYID_20_DATA_BLOCK);
|
|
// This CTA 861 function to parse 861 part
|
|
parse861bShortTiming(p861Info, pDisplayIdInfo, FROM_DISPLAYID_20_DATA_BLOCK);
|
|
// yuv420-only video
|
|
parse861bShortYuv420Timing(p861Info, pDisplayIdInfo, FROM_DISPLAYID_20_DATA_BLOCK);
|
|
|
|
if (pDisplayIdInfo->cta.cta861_info.valid.hdr_static_metadata != 0)
|
|
{
|
|
parseCta861HdrStaticMetadataDataBlock(p861Info, pDisplayIdInfo, FROM_DISPLAYID_20_DATA_BLOCK);
|
|
}
|
|
|
|
// CEA861-F at 7.5.12 section about VFPDB block.
|
|
if (p861Info->total_svr > 0)
|
|
{
|
|
parseCta861NativeOrPreferredTiming(p861Info, pDisplayIdInfo, FROM_DISPLAYID_20_DATA_BLOCK);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
// Helper function
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
static NvU32
|
|
greatestCommonDenominator(
|
|
NvU32 x,
|
|
NvU32 y)
|
|
{
|
|
NvU32 g = 0;
|
|
|
|
while (x > 0)
|
|
{
|
|
g = x;
|
|
x = y % x;
|
|
y = g;
|
|
}
|
|
return g;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
static NVT_STATUS
|
|
getPrimaryUseCase(
|
|
NvU8 product_type,
|
|
NVT_DISPLAYID_PRODUCT_PRIMARY_USE_CASE *primary_use_case)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
|
|
switch (product_type)
|
|
{
|
|
case DISPLAYID_2_0_PROD_TEST:
|
|
*primary_use_case = PRODUCT_PRIMARY_USE_TEST_EQUIPMENT;
|
|
break;
|
|
case DISPLAYID_2_0_PROD_GENERIC_DISPLAY:
|
|
*primary_use_case = PRODUCT_PRIMARY_USE_GENERIC_DISPLAY;
|
|
break;
|
|
case DISPLAYID_2_0_PROD_TELEVISION:
|
|
*primary_use_case = PRODUCT_PRIMARY_USE_TELEVISION;
|
|
break;
|
|
case DISPLAYID_2_0_PROD_DESKTOP_PRODUCTIVITY_DISPLAY:
|
|
*primary_use_case = PRODUCT_PRIMARY_USE_DESKTOP_PRODUCTIVITY;
|
|
break;
|
|
case DISPLAYID_2_0_PROD_DESKTOP_GAMING_DISPLAY:
|
|
*primary_use_case = PRODUCT_PRIMARY_USE_DESKTOP_GAMING;
|
|
break;
|
|
case DISPLAYID_2_0_PROD_PRESENTATION_DISPLAY:
|
|
*primary_use_case = PRODUCT_PRIMARY_USE_PRESENTATION;
|
|
break;
|
|
case DISPLAYID_2_0_PROD_HMD_VR:
|
|
*primary_use_case = PRODUCT_PRIMARY_USE_HEAD_MOUNT_VIRTUAL_REALITY;
|
|
break;
|
|
case DISPLAYID_2_0_PROD_HMD_AR:
|
|
*primary_use_case = PRODUCT_PRIMARY_USE_HEAD_MOUNT_AUGMENTED_REALITY;
|
|
break;
|
|
case DISPLAYID_2_0_PROD_EXTENSION:
|
|
status = NVT_STATUS_ERR;
|
|
break;
|
|
default:
|
|
status = NVT_STATUS_ERR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
// used in DID20 and DID20ext
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NvU8
|
|
computeDisplayId20SectionCheckSum(
|
|
const NvU8 *pSectionBytes,
|
|
NvU32 length)
|
|
{
|
|
|
|
NvU32 i = 0;
|
|
NvU32 checkSum = 0;
|
|
|
|
// Each DisplayID section composed of five mandatory bytes:
|
|
// DisplayID Structure Version and Revision
|
|
// Section Size
|
|
// Product Primary Use Case
|
|
// Extension Count
|
|
// Checksum
|
|
for (i = 0, checkSum = 0; i < length; i++)
|
|
{
|
|
checkSum += pSectionBytes[i];
|
|
}
|
|
|
|
return (checkSum & 0xFF);
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NvBool
|
|
assignNextAvailableDisplayId20Timing(
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo,
|
|
const NVT_TIMING *pTiming)
|
|
{
|
|
if (pDisplayIdInfo == NULL) return NV_TRUE;
|
|
|
|
if (pDisplayIdInfo->total_timings >= COUNT(pDisplayIdInfo->timing))
|
|
{
|
|
return NV_FALSE;
|
|
}
|
|
|
|
pDisplayIdInfo->timing[pDisplayIdInfo->total_timings] = *pTiming;
|
|
pDisplayIdInfo->total_timings++;
|
|
|
|
return NV_TRUE;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20Timing7Descriptor(
|
|
const void *pVoidDescriptor,
|
|
NVT_TIMING *pTiming,
|
|
NvU8 count)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
NvU32 gdc = 0;
|
|
|
|
const DISPLAYID_2_0_TIMING_7_DESCRIPTOR *pDescriptor = NULL;
|
|
|
|
pDescriptor = (const DISPLAYID_2_0_TIMING_7_DESCRIPTOR *)pVoidDescriptor;
|
|
|
|
// pclk is in 1Khz
|
|
pTiming->pclk1khz = ((pDescriptor->pixel_clock[2] << 16 |
|
|
pDescriptor->pixel_clock[1] << 8 |
|
|
pDescriptor->pixel_clock[0]) + 1);
|
|
|
|
pTiming->HBorder = 0;
|
|
pTiming->VBorder = 0;
|
|
|
|
pTiming->HVisible = ((pDescriptor->horizontal.active_image_pixels[1] << 8) |
|
|
(pDescriptor->horizontal.active_image_pixels[0])) + 1;
|
|
pTiming->VVisible = ((pDescriptor->vertical.active_image_lines[1] << 8) |
|
|
(pDescriptor->vertical.active_image_lines[0])) + 1;
|
|
|
|
pTiming->HTotal = (((pDescriptor->horizontal.blank_pixels[1] << 8) |
|
|
(pDescriptor->horizontal.blank_pixels[0])) + 1) +
|
|
pTiming->HVisible;
|
|
pTiming->VTotal = (((pDescriptor->vertical.blank_lines[1] << 8) |
|
|
(pDescriptor->vertical.blank_lines[0])) + 1) +
|
|
pTiming->VVisible;
|
|
|
|
pTiming->HFrontPorch = ((pDescriptor->horizontal.front_porch_pixels_high << 8) |
|
|
(pDescriptor->horizontal.front_porch_pixels_low)) + 1;
|
|
pTiming->VFrontPorch = ((pDescriptor->vertical.front_porch_lines_high << 8) |
|
|
(pDescriptor->vertical.front_porch_lines_low)) + 1;
|
|
|
|
pTiming->HSyncWidth = ((pDescriptor->horizontal.sync_width_pixels[1] << 8) |
|
|
(pDescriptor->horizontal.sync_width_pixels[0])) + 1;
|
|
pTiming->VSyncWidth = ((pDescriptor->vertical.sync_width_lines[1] << 8) |
|
|
(pDescriptor->vertical.sync_width_lines[0])) + 1;
|
|
|
|
pTiming->HSyncPol = pDescriptor->horizontal.sync_polarity ? NVT_H_SYNC_POSITIVE :
|
|
NVT_H_SYNC_NEGATIVE;
|
|
pTiming->VSyncPol = pDescriptor->vertical.sync_polarity ? NVT_V_SYNC_POSITIVE :
|
|
NVT_V_SYNC_NEGATIVE;
|
|
|
|
// EDID used in DP1.4 Compliance test had incorrect HBlank listed, leading to wrong raster sizes being set by driver (bug 2714607)
|
|
// Filter incorrect timings here. HTotal must cover sufficient blanking time
|
|
if (pTiming->HTotal < (pTiming->HVisible + pTiming->HFrontPorch + pTiming->HSyncWidth))
|
|
{
|
|
return NVT_STATUS_ERR;
|
|
}
|
|
|
|
pTiming->interlaced = pDescriptor->options.interface_frame_scanning_type;
|
|
|
|
switch (pDescriptor->options.aspect_ratio)
|
|
{
|
|
case DISPLAYID_2_0_TIMING_ASPECT_RATIO_1_1:
|
|
pTiming->etc.aspect = (1 << 16) | 1;
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_ASPECT_RATIO_5_4:
|
|
pTiming->etc.aspect = (5 << 16) | 4;
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_ASPECT_RATIO_4_3:
|
|
pTiming->etc.aspect = (4 << 16) | 3;
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_ASPECT_RATIO_15_9:
|
|
pTiming->etc.aspect = (15 << 16) | 9;
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_ASPECT_RATIO_16_9:
|
|
pTiming->etc.aspect = (16 << 16) | 9;
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_ASPECT_RATIO_16_10:
|
|
pTiming->etc.aspect = (16 << 16) | 10;
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_ASPECT_RATIO_64_27:
|
|
pTiming->etc.aspect = (64 << 16) | 27;
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_ASPECT_RATIO_256_135:
|
|
pTiming->etc.aspect = (256 << 16) | 135;
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_ASPECT_RATIO_CALCULATE:
|
|
gdc = greatestCommonDenominator(pTiming->HVisible, pTiming->VVisible);
|
|
if (gdc != 0)
|
|
{
|
|
pTiming->etc.aspect = ((pTiming->HVisible / gdc) << 16) |
|
|
(pTiming->VVisible / gdc);
|
|
}
|
|
else
|
|
{
|
|
pTiming->etc.aspect = 0;
|
|
}
|
|
break;
|
|
default:
|
|
pTiming->etc.aspect = 0;
|
|
}
|
|
|
|
pTiming->etc.rr = NvTiming_CalcRR(pTiming->pclk1khz,
|
|
pTiming->interlaced,
|
|
pTiming->HTotal,
|
|
pTiming->VTotal) / 10;
|
|
pTiming->etc.rrx1k = NvTiming_CalcRRx1k(pTiming->pclk1khz,
|
|
pTiming->interlaced,
|
|
pTiming->HTotal,
|
|
pTiming->VTotal) / 10;
|
|
|
|
// pclk change to 10kHz
|
|
pTiming->pclk = pTiming->pclk1khz / 10;
|
|
|
|
pTiming->etc.status = NVT_STATUS_DISPLAYID_7N(++count);
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20Timing8Descriptor(
|
|
const void *pVoidDescriptor,
|
|
NVT_TIMING *pTiming,
|
|
NvU8 codeType,
|
|
NvU8 codeSize,
|
|
NvU8 idx,
|
|
NvU8 count)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
|
|
const NvU8 *pTimingCode = (const NvU8 *)pVoidDescriptor;
|
|
const NvU16 *pTiming2ByteCode = (const NvU16 *)pVoidDescriptor;
|
|
|
|
if (codeSize == DISPLAYID_2_0_TIMING_CODE_SIZE_1_BYTE)
|
|
{
|
|
switch (codeType)
|
|
{
|
|
case DISPLAYID_2_0_TIMING_CODE_DMT: //single-byte DMT ID Codes
|
|
status = NvTiming_EnumDMT((NvU32)(pTimingCode[idx]), pTiming);
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_CODE_CTA_VIC:
|
|
status = NvTiming_EnumCEA861bTiming((NvU32)(pTimingCode[idx]), pTiming);
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_CODE_HDMI_VIC:
|
|
status = NvTiming_EnumHdmiVsdbExtendedTiming((NvU32)(pTimingCode[idx]), pTiming);
|
|
break;
|
|
default:
|
|
{
|
|
nvt_assert(0 && "RESERVED timing code type");
|
|
status = NVT_STATUS_ERR;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (codeSize == DISPLAYID_2_0_TIMING_CODE_SIZE_2_BYTE)
|
|
{
|
|
// Standard two-byte codes
|
|
if (codeType == DISPLAYID_2_0_TIMING_CODE_DMT)
|
|
{
|
|
status = NvTiming_EnumStdTwoBytesCode((NvU16)pTiming2ByteCode[idx], pTiming);
|
|
}
|
|
}
|
|
|
|
if (status == NVT_STATUS_SUCCESS)
|
|
{
|
|
pTiming->etc.status = NVT_STATUS_DISPLAYID_8N(++count);
|
|
return status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20Timing9Descriptor(
|
|
const void *pVoidDescriptor,
|
|
NVT_TIMING *pTiming,
|
|
NvU8 count)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
const DISPLAYID_2_0_TIMING_9_DESCRIPTOR* pDescriptor = NULL;
|
|
NvU32 width = 0;
|
|
NvU32 height = 0;
|
|
NvU32 rr = 0;
|
|
|
|
pDescriptor = (const DISPLAYID_2_0_TIMING_9_DESCRIPTOR *)pVoidDescriptor;
|
|
|
|
width = (pDescriptor->horizontal_active_pixels[1] << 8 | pDescriptor->horizontal_active_pixels[0]) + 1;
|
|
height = (pDescriptor->vertical_active_lines[1] << 8 | pDescriptor->vertical_active_lines[0]) + 1;
|
|
rr = pDescriptor->refresh_rate + 1;
|
|
|
|
switch (pDescriptor->options.timing_formula)
|
|
{
|
|
case DISPLAYID_2_0_TIMING_FORMULA_CVT_1_2_STANDARD_CRT_BASED:
|
|
status = NvTiming_CalcCVT(width, height, rr, NVT_PROGRESSIVE, pTiming);
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_FORMULA_CVT_1_2_REDUCED_BLANKING_1:
|
|
status = NvTiming_CalcCVT_RB(width, height, rr, NVT_PROGRESSIVE, pTiming);
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_FORMULA_CVT_2_1_REDUCED_BLANKING_2:
|
|
status = NvTiming_CalcCVT_RB2(width, height, rr, pDescriptor->options.rr_1000div1001_support, NV_FALSE, pTiming);
|
|
break;
|
|
default:
|
|
{
|
|
nvt_assert(0 && "Unknown timing formula");
|
|
status = NVT_STATUS_ERR;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (status == NVT_STATUS_SUCCESS)
|
|
{
|
|
NVMISC_MEMSET(pTiming->etc.name, 0, sizeof(pTiming->etc.name));
|
|
pTiming->etc.status = NVT_STATUS_DISPLAYID_9N(++count);
|
|
|
|
if (pDescriptor->options.timing_formula == DISPLAYID_2_0_TIMING_FORMULA_CVT_1_2_STANDARD_CRT_BASED)
|
|
{
|
|
NVT_SNPRINTF((char *)pTiming->etc.name, sizeof(pTiming->etc.name), "DID20-Type9:#%3d:%dx%dx%3d.%03dHz/%s",
|
|
(int)NVT_GET_TIMING_STATUS_SEQ(pTiming->etc.status),
|
|
(int)pTiming->HVisible,
|
|
(int)pTiming->VVisible,
|
|
(int)pTiming->etc.rrx1k/1000,
|
|
(int)pTiming->etc.rrx1k%1000,
|
|
(pTiming->interlaced ? "I":"P"));
|
|
}
|
|
else
|
|
{
|
|
NVT_SNPRINTF((char *)pTiming->etc.name, sizeof(pTiming->etc.name), "DID20-Type9RB%d:#%3d:%dx%dx%3d.%03dHz/%s",
|
|
pDescriptor->options.timing_formula,
|
|
(int)NVT_GET_TIMING_STATUS_SEQ(pTiming->etc.status),
|
|
(int)pTiming->HVisible,
|
|
(int)pTiming->VVisible,
|
|
(int)pTiming->etc.rrx1k/1000,
|
|
(int)pTiming->etc.rrx1k%1000,
|
|
(pTiming->interlaced ? "I":"P"));
|
|
}
|
|
}
|
|
pTiming->etc.name[sizeof(pTiming->etc.name) - 1] = '\0';
|
|
pTiming->etc.rep = 0x1;
|
|
|
|
return status;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NVT_STATUS
|
|
parseDisplayId20Timing10Descriptor(
|
|
const void *pDescriptor,
|
|
NVT_TIMING *pTiming,
|
|
NvU8 payloadBytes,
|
|
NvU8 count)
|
|
{
|
|
NVT_STATUS status = NVT_STATUS_SUCCESS;
|
|
const DISPLAYID_2_0_TIMING_10_6BYTES_DESCRIPTOR* p6bytesDescriptor = NULL;
|
|
const DISPLAYID_2_0_TIMING_10_7BYTES_DESCRIPTOR* p7bytesDescriptor = NULL;
|
|
const DISPLAYID_2_1_TIMING_10_8BYTES_DESCRIPTOR* p8bytesDescriptor = NULL;
|
|
NvU32 width = 0;
|
|
NvU32 height = 0;
|
|
NvU32 rr = 0;
|
|
|
|
p6bytesDescriptor = (const DISPLAYID_2_0_TIMING_10_6BYTES_DESCRIPTOR *)pDescriptor;
|
|
|
|
width = (p6bytesDescriptor->horizontal_active_pixels[1] << 8 | p6bytesDescriptor->horizontal_active_pixels[0]) + 1;
|
|
height = (p6bytesDescriptor->vertical_active_lines[1] << 8 | p6bytesDescriptor->vertical_active_lines[0]) + 1;
|
|
rr = p6bytesDescriptor->refresh_rate + 1;
|
|
|
|
if (payloadBytes == DISPLAYID_2_0_TIMING_10_PAYLOAD_BYTES_7)
|
|
{
|
|
p7bytesDescriptor = (const DISPLAYID_2_0_TIMING_10_7BYTES_DESCRIPTOR *)pDescriptor;
|
|
rr = (p7bytesDescriptor->descriptor_6_bytes.refresh_rate | p7bytesDescriptor->refresh_rate_high << 8) + 1;
|
|
}
|
|
else if (payloadBytes == DISPLAYID_2_1_TIMING_10_PAYLOAD_BYTES_8)
|
|
{
|
|
p8bytesDescriptor = (const DISPLAYID_2_1_TIMING_10_8BYTES_DESCRIPTOR *)pDescriptor;
|
|
rr = (p8bytesDescriptor->descriptor_7_bytes.descriptor_6_bytes.refresh_rate |
|
|
p8bytesDescriptor->descriptor_7_bytes.refresh_rate_high << 8) + 1;
|
|
}
|
|
|
|
switch (p6bytesDescriptor->options.timing_formula)
|
|
{
|
|
case DISPLAYID_2_0_TIMING_FORMULA_CVT_1_2_STANDARD_CRT_BASED:
|
|
status = NvTiming_CalcCVT(width, height, rr, NVT_PROGRESSIVE, pTiming);
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_FORMULA_CVT_1_2_REDUCED_BLANKING_1:
|
|
status = NvTiming_CalcCVT_RB(width, height, rr, NVT_PROGRESSIVE, pTiming);
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_FORMULA_CVT_2_1_REDUCED_BLANKING_2:
|
|
if (p8bytesDescriptor != NULL)
|
|
{
|
|
status = NvTiming_CalcCVT_RB2(width, height, rr, p6bytesDescriptor->options.rr1000div1001_or_hblank, p8bytesDescriptor->additional_mini_vblank, pTiming);
|
|
}
|
|
else
|
|
{
|
|
status = NvTiming_CalcCVT_RB2(width, height, rr, p6bytesDescriptor->options.rr1000div1001_or_hblank, NV_FALSE, pTiming);
|
|
}
|
|
|
|
break;
|
|
case DISPLAYID_2_0_TIMING_FORMULA_CVT_2_1_REDUCED_BLANKING_3:
|
|
{
|
|
NvU32 deltaHBlank = 0;
|
|
NvU32 multiplier = DISPLAYID_2_0_TIMING_10_NOMINAL_MINIMUM_VBLANK;
|
|
|
|
if (p7bytesDescriptor != NULL)
|
|
{
|
|
if (p6bytesDescriptor->options.rr1000div1001_or_hblank == 0) // Horizontal Blank in Pixels = [Field Value] * 8 + 80
|
|
{
|
|
deltaHBlank = p7bytesDescriptor->delta_hblank * 8;
|
|
}
|
|
else if (p6bytesDescriptor->options.rr1000div1001_or_hblank == 1)
|
|
{
|
|
if (p7bytesDescriptor->delta_hblank <= 5)
|
|
deltaHBlank = (p7bytesDescriptor->delta_hblank * 8 + 160) - 80;
|
|
else // if 5 < Field Value <=7
|
|
deltaHBlank = (160 - ((p7bytesDescriptor->delta_hblank - 5) * 8)) - 80;
|
|
}
|
|
|
|
status = NvTiming_CalcCVT_RB3(width,
|
|
height,
|
|
rr,
|
|
deltaHBlank,
|
|
p7bytesDescriptor->additional_vblank_timing * multiplier,
|
|
0,
|
|
p6bytesDescriptor->options.early_vsync,
|
|
pTiming);
|
|
|
|
}
|
|
else if (p8bytesDescriptor != NULL)
|
|
{
|
|
if (p6bytesDescriptor->options.rr1000div1001_or_hblank == 0) // Horizontal Blank in Pixels = [Field Value] * 8 + 80
|
|
{
|
|
deltaHBlank = p8bytesDescriptor->descriptor_7_bytes.delta_hblank * 8;
|
|
}
|
|
else if (p6bytesDescriptor->options.rr1000div1001_or_hblank == 1)
|
|
{
|
|
if (p8bytesDescriptor->descriptor_7_bytes.delta_hblank <= 5)
|
|
deltaHBlank = (p8bytesDescriptor->descriptor_7_bytes.delta_hblank * 8 + 160) - 80;
|
|
else // if 5 < Field Value <=7
|
|
deltaHBlank = (160 - ((p8bytesDescriptor->descriptor_7_bytes.delta_hblank - 5) * 8)) - 80;
|
|
}
|
|
|
|
if (p8bytesDescriptor->additional_mini_vblank == 1)
|
|
multiplier = DISPLAYID_2_1_TIMING_10_ALTERNATE_MINIMUM_VBLANK;
|
|
|
|
status = NvTiming_CalcCVT_RB3(width,
|
|
height,
|
|
rr,
|
|
deltaHBlank,
|
|
p8bytesDescriptor->descriptor_7_bytes.additional_vblank_timing * multiplier,
|
|
p8bytesDescriptor->additional_mini_vblank,
|
|
p6bytesDescriptor->options.early_vsync,
|
|
pTiming);
|
|
}
|
|
else // 6 bytes descriptor
|
|
{
|
|
// just assign the HBlank 80pixel but actually HBlank is 160 in DisplayId2.1a spec
|
|
if (p6bytesDescriptor->options.rr1000div1001_or_hblank == 1)
|
|
deltaHBlank = 80;
|
|
|
|
status = NvTiming_CalcCVT_RB3(width, height, rr, deltaHBlank, 0, 0, p6bytesDescriptor->options.early_vsync, pTiming);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
nvt_assert(0 && "Unknown timing formula");
|
|
status = NVT_STATUS_ERR;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (status == NVT_STATUS_SUCCESS)
|
|
{
|
|
pTiming->etc.status = NVT_STATUS_DISPLAYID_10N(++count);
|
|
return status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
// get the existed stored timing sequence number
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
static NvU8
|
|
getExistedTimingSeqNumber(
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayIdInfo,
|
|
enum NVT_TIMING_TYPE timingType)
|
|
{
|
|
NvU8 count = 0;
|
|
NvU8 i = 0;
|
|
|
|
switch (timingType)
|
|
{
|
|
case NVT_TYPE_DISPLAYID_7:
|
|
case NVT_TYPE_DISPLAYID_8:
|
|
case NVT_TYPE_DISPLAYID_9:
|
|
case NVT_TYPE_DISPLAYID_10:
|
|
break;
|
|
default:
|
|
return count;
|
|
}
|
|
|
|
for (i = 0; i< pDisplayIdInfo->total_timings; i++)
|
|
{
|
|
if (NVT_GET_TIMING_STATUS_TYPE(pDisplayIdInfo->timing[i].etc.status) == timingType)
|
|
{
|
|
++count;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
// get the version
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
NvU32 getDID2Version(NvU8 *pData, NvU32 *pVer)
|
|
{
|
|
const DISPLAYID_2_0_SECTION *pSection = (const DISPLAYID_2_0_SECTION*)pData;
|
|
|
|
*pVer = 0;
|
|
if (pSection->header.version == 0x2)
|
|
{
|
|
*pVer = (((NvU32)pSection->header.version) << 8) + ((NvU32)pSection->header.revision);
|
|
}
|
|
else
|
|
return NVT_STATUS_ERR; // un-recongnized DisplayID20 version
|
|
|
|
return NVT_STATUS_SUCCESS;
|
|
}
|
|
|
|
CODE_SEGMENT(PAGE_DD_CODE)
|
|
void
|
|
updateColorFormatForDisplayId20Timings(
|
|
NVT_DISPLAYID_2_0_INFO *pDisplayId20Info,
|
|
NvU32 timingIdx)
|
|
{
|
|
// pDisplayId20Info parsed displayID20 info
|
|
NVT_TIMING *pT= &pDisplayId20Info->timing[timingIdx];
|
|
|
|
nvt_assert(timingIdx <= COUNT(pDisplayId20Info->timing));
|
|
|
|
// rgb444 (always support 6bpc and 8bpc as per DP spec 5.1.1.1.1 RGB Colorimetry)
|
|
UPDATE_BPC_FOR_COLORFORMAT(pT->etc.rgb444, 1,
|
|
1,
|
|
pDisplayId20Info->interface_features.rgb444.bpc.bpc10,
|
|
pDisplayId20Info->interface_features.rgb444.bpc.bpc12,
|
|
pDisplayId20Info->interface_features.rgb444.bpc.bpc14,
|
|
pDisplayId20Info->interface_features.rgb444.bpc.bpc16);
|
|
|
|
// yuv444
|
|
UPDATE_BPC_FOR_COLORFORMAT(pT->etc.yuv444, 0, // yuv444 does not support 6bpc
|
|
pDisplayId20Info->interface_features.yuv444.bpc.bpc8,
|
|
pDisplayId20Info->interface_features.yuv444.bpc.bpc10,
|
|
pDisplayId20Info->interface_features.yuv444.bpc.bpc12,
|
|
pDisplayId20Info->interface_features.yuv444.bpc.bpc14,
|
|
pDisplayId20Info->interface_features.yuv444.bpc.bpc16);
|
|
// yuv422
|
|
UPDATE_BPC_FOR_COLORFORMAT(pT->etc.yuv422, 0, // yuv422 does not support 6bpc
|
|
pDisplayId20Info->interface_features.yuv422.bpc.bpc8,
|
|
pDisplayId20Info->interface_features.yuv422.bpc.bpc10,
|
|
pDisplayId20Info->interface_features.yuv422.bpc.bpc12,
|
|
pDisplayId20Info->interface_features.yuv422.bpc.bpc14,
|
|
pDisplayId20Info->interface_features.yuv422.bpc.bpc16);
|
|
|
|
if (!NVT_DID20_TIMING_IS_CTA861(pT->etc.flag, pT->etc.status))
|
|
{
|
|
// yuv420
|
|
UPDATE_BPC_FOR_COLORFORMAT(pT->etc.yuv420, 0, // yuv420 does not support 6bpc
|
|
pDisplayId20Info->interface_features.yuv420.bpc.bpc8,
|
|
pDisplayId20Info->interface_features.yuv420.bpc.bpc10,
|
|
pDisplayId20Info->interface_features.yuv420.bpc.bpc12,
|
|
pDisplayId20Info->interface_features.yuv420.bpc.bpc14,
|
|
pDisplayId20Info->interface_features.yuv420.bpc.bpc16);
|
|
}
|
|
}
|
|
POP_SEGMENTS
|
|
|