diff --git a/src/common/displayport/src/dp_configcaps.cpp b/src/common/displayport/src/dp_configcaps.cpp index 340a3d9b5..dd90f8af3 100644 --- a/src/common/displayport/src/dp_configcaps.cpp +++ b/src/common/displayport/src/dp_configcaps.cpp @@ -185,6 +185,12 @@ void DPCDHALImpl::parseAndReadCaps() // Set an invalid state here and make sure we REMEMBER we couldn't get the caps caps.revisionMajor = 0; dpcdOffline = true; + + // + // Forced/sink-less connector (EDID override, no AUX): fall back to + // fake caps so discovery can proceed and create a device. + // + populateFakeDpcd(); return; } @@ -634,6 +640,14 @@ bool DPCDHALImpl::getSDPExtnForColorimetry() { bool bSDPExtnForColorimetry = false; NvU8 byte = 0; + if (dpcdOffline) + { + // + // Forced/sink-less connector: claim VSC SDP colorimetry support so + // HDR signaling can be enabled. No real sink interprets the SDP. + // + return true; + } if (caps.extendedRxCapsPresent) { if (AuxRetry::ack == bus.read(NV_DPCD14_EXTENDED_DPRX_FEATURE_ENUM_LIST, &byte, sizeof byte)) @@ -996,7 +1010,7 @@ void DPCDHALImpl::populateFakeDpcd() // this should be extended in for more dpcd offsets in future. // caps.revisionMajor = 0x1; - caps.revisionMinor = 0x1; + caps.revisionMinor = 0x4; caps.supportsESI = false; caps.maxLinkRate = dp2LinkRate_8_10Gbps; caps.maxLaneCount = 4; diff --git a/src/common/displayport/src/dp_deviceimpl.cpp b/src/common/displayport/src/dp_deviceimpl.cpp index 9d1313e5c..117a12cd4 100644 --- a/src/common/displayport/src/dp_deviceimpl.cpp +++ b/src/common/displayport/src/dp_deviceimpl.cpp @@ -1732,6 +1732,15 @@ NvBool DeviceImpl::getDSCSupport() } } + else if (hal->isDpcdOffline()) + { + // + // Forced/sink-less connector (EDID override, no AUX): assume the + // virtual sink can decompress DSC so that high-bandwidth modes pass + // validation. The stream is never decoded by a real device. + // + dscCaps.bDSCDecompressionSupported = true; + } else { DP_PRINTF(DP_ERROR, "DP-DEV> DSC Support AUX READ failed for %s!", address.toString(sb)); @@ -2308,6 +2317,11 @@ bool DeviceImpl::getFECSupport() bFECSupported = this->bandwidth.enum_path.bPathFECCapable; } + else if (hal->isDpcdOffline()) + { + // Forced/sink-less connector: claim FEC so the DSC path is usable. + bFECSupported = true; + } else if (AuxBus::success == this->getDpcdData(NV_DPCD14_FEC_CAPABILITY, &byte, sizeof(byte), &size, &nakReason)) { @@ -2560,6 +2574,30 @@ bool DeviceImpl::readAndParseDSCCaps() if(AuxBus::success != this->getDpcdData(NV_DPCD14_DSC_SUPPORT, &rawDscCaps[0], sizeof(rawDscCaps), &sizeCompleted, &nakReason)) { + if (hal->isDpcdOffline()) + { + // + // Forced/sink-less connector: synthesize DSC decoder caps + // modeled on a typical DSC 1.2 4K high-refresh monitor. + // + rawDscCaps[0x0] = 0x01; // decompression supported + rawDscCaps[0x1] = 0x21; // DSC algorithm revision 1.2 + rawDscCaps[0x2] = 0x00; // RC buffer block size + rawDscCaps[0x3] = 0x0F; // RC buffer size + rawDscCaps[0x4] = 0xFF; // slice caps 1: up to 12 slices + rawDscCaps[0x5] = 0x03; // line buffer bit depth: 12 + rawDscCaps[0x6] = 0x01; // block prediction supported + rawDscCaps[0x7] = 0xFF; // max bits per pixel LSB + rawDscCaps[0x8] = 0x03; // max bits per pixel MSB (1023/16 bpp) + rawDscCaps[0x9] = 0x1F; // color formats: RGB + all YCbCr + rawDscCaps[0xA] = 0x0E; // color depth: 8/10/12 bpc + rawDscCaps[0xB] = 0xEE; // peak throughput 1000 MP/s both modes + rawDscCaps[0xC] = 0x10; // max slice width 5120 px + rawDscCaps[0xD] = 0x00; // slice caps 2 + rawDscCaps[0xE] = 0x00; // branch throughput + rawDscCaps[0xF] = 0x00; // bpp increment: 1/16 + return parseDscCaps(&rawDscCaps[0], sizeof(rawDscCaps)); + } DP_PRINTF(DP_ERROR, "DP-DEV> Error querying DSC Caps on %s!", this->address.toString(sb)); return false; } diff --git a/src/nvidia-modeset/include/dp/nvdp-connector.h b/src/nvidia-modeset/include/dp/nvdp-connector.h index 27304b915..3996c7b93 100644 --- a/src/nvidia-modeset/include/dp/nvdp-connector.h +++ b/src/nvidia-modeset/include/dp/nvdp-connector.h @@ -37,6 +37,8 @@ void nvDPNotifyLongPulse(NVConnectorEvoPtr pConnectorEvo, void nvDPNotifyShortPulse(NVDPLibConnectorPtr pNVDpLibConnector); +NvBool nvDPConnectorIsPlugged(const NVConnectorEvoRec *pConnectorEvo); + void nvDPDestroyConnector(NVDPLibConnectorPtr pNVDpLibConnector); NVDPLibModesetStatePtr nvDPLibCreateModesetState( diff --git a/src/nvidia-modeset/src/dp/nvdp-connector.cpp b/src/nvidia-modeset/src/dp/nvdp-connector.cpp index 61cb523b1..a8a552a4a 100644 --- a/src/nvidia-modeset/src/dp/nvdp-connector.cpp +++ b/src/nvidia-modeset/src/dp/nvdp-connector.cpp @@ -121,6 +121,12 @@ void nvDPNotifyLongPulse(NVConnectorEvoPtr pConnectorEvo, } +NvBool nvDPConnectorIsPlugged(const NVConnectorEvoRec *pConnectorEvo) +{ + return (pConnectorEvo->pDpLibConnector != NULL) && + pConnectorEvo->pDpLibConnector->plugged; +} + void nvDPNotifyShortPulse(NVDPLibConnectorPtr pNVDpLibConnector) { DisplayPort::Connector *c = pNVDpLibConnector->connector; diff --git a/src/nvidia-modeset/src/nvkms-dpy.c b/src/nvidia-modeset/src/nvkms-dpy.c index 7fc92fcfd..c9f7ae66b 100644 --- a/src/nvidia-modeset/src/nvkms-dpy.c +++ b/src/nvidia-modeset/src/nvkms-dpy.c @@ -22,6 +22,7 @@ */ #include "dp/nvdp-device.h" +#include "dp/nvdp-connector.h" #include "dp/nvdp-connector-event-sink.h" #include "nvkms-api-types.h" @@ -3127,6 +3128,15 @@ NvBool nvDpyGetDynamicData( connectedList = nvDPLibDpyIsConnected(pDpyEvo) ? oneDpyIdList : nvEmptyDpyIdList(); } else if (pRequest->forceConnected) { + if (nvConnectorUsesDPLib(pConnectorEvo) && + !nvDPConnectorIsPlugged(pConnectorEvo)) { + /* + * Forced sink-less DP connector (EDID override): simulate a + * plug so the DP library performs discovery and creates a + * device, enabling DSC/HDR capability paths to be consulted. + */ + nvDPNotifyLongPulse(pConnectorEvo, TRUE); + } connectedList = oneDpyIdList; } else if (pRequest->forceDisconnected) { connectedList = nvEmptyDpyIdList();