From 6c62386cce62159726c0d2fa0fe5b1a4c48d2c36 Mon Sep 17 00:00:00 2001 From: Rohithmatham12 Date: Thu, 11 Jun 2026 18:14:04 -0400 Subject: [PATCH] dp: scope virtual sink caps to forced connectors --- src/common/displayport/inc/dp_configcaps.h | 16 +++++++- src/common/displayport/inc/dp_connector.h | 1 + src/common/displayport/inc/dp_connectorimpl.h | 1 + src/common/displayport/src/dp_configcaps.cpp | 19 ++++++++- .../displayport/src/dp_connectorimpl.cpp | 14 ++++++- src/common/displayport/src/dp_deviceimpl.cpp | 39 +++++++++++++++++++ .../include/dp/nvdp-connector.h | 5 +++ src/nvidia-modeset/src/dp/nvdp-connector.cpp | 16 ++++++++ src/nvidia-modeset/src/nvkms-dpy.c | 10 +++++ 9 files changed, 118 insertions(+), 3 deletions(-) diff --git a/src/common/displayport/inc/dp_configcaps.h b/src/common/displayport/inc/dp_configcaps.h index 01dbaa79f4..c1191473a9 100644 --- a/src/common/displayport/inc/dp_configcaps.h +++ b/src/common/displayport/inc/dp_configcaps.h @@ -305,6 +305,8 @@ namespace DisplayPort virtual void overrideOptimalLinkRate(LinkRate optimalLinkRate) = 0; virtual bool isDpcdOffline() = 0; + virtual bool isVirtualSinkDpcdFallback() = 0; + virtual void setVirtualSinkDpcdFallback(bool bEnable) = 0; virtual void setAuxBus(AuxBus * bus) = 0; virtual NvU32 getVideoFallbackSupported() = 0; // @@ -596,6 +598,7 @@ namespace DisplayPort AuxRetry bus; Timer * timer; bool dpcdOffline; + bool bVirtualSinkDpcdFallback; bool bGrantsPostLtRequest; bool pc2Disabled; bool uprequestEnable; @@ -795,7 +798,8 @@ namespace DisplayPort public: DPCDHALImpl(AuxBus * bus, Timer * timer) - : bus(bus), timer(timer), bGrantsPostLtRequest(false), uprequestEnable(false), + : bus(bus), timer(timer), bVirtualSinkDpcdFallback(false), + bGrantsPostLtRequest(false), uprequestEnable(false), upstreamIsSource(false), bMultistream(false), bGpuFECSupported(false), bBypassILREdpRevCheck(false), overrideDpcdMaxLinkRate(0), overrideDpcdRev(0), gpuDPSupportedVersions(0) @@ -834,6 +838,16 @@ namespace DisplayPort return dpcdOffline; } + bool isVirtualSinkDpcdFallback() + { + return bVirtualSinkDpcdFallback; + } + + void setVirtualSinkDpcdFallback(bool bEnable) + { + bVirtualSinkDpcdFallback = bEnable; + } + void setDPCDOffline(bool bOffline) { dpcdOffline = bOffline; diff --git a/src/common/displayport/inc/dp_connector.h b/src/common/displayport/inc/dp_connector.h index 7b48ce0853..c71315085e 100644 --- a/src/common/displayport/inc/dp_connector.h +++ b/src/common/displayport/inc/dp_connector.h @@ -630,6 +630,7 @@ namespace DisplayPort // Notify library of hotplug/IRQ virtual void notifyLongPulse(bool statusConnected) = 0; + virtual void notifyVirtualSinkLongPulse(bool statusConnected) = 0; virtual void notifyShortPulse() = 0; // Notify Library when ACPI initialization is done diff --git a/src/common/displayport/inc/dp_connectorimpl.h b/src/common/displayport/inc/dp_connectorimpl.h index 63cdd54b41..40d32bda9f 100644 --- a/src/common/displayport/inc/dp_connectorimpl.h +++ b/src/common/displayport/inc/dp_connectorimpl.h @@ -760,6 +760,7 @@ namespace DisplayPort virtual void disconnectDeviceList(); void notifyLongPulseInternal(bool statusConnected); virtual void notifyLongPulse(bool status); + virtual void notifyVirtualSinkLongPulse(bool status); virtual void notifyShortPulse(); virtual Group * newGroup(); virtual void destroy(); diff --git a/src/common/displayport/src/dp_configcaps.cpp b/src/common/displayport/src/dp_configcaps.cpp index 340a3d9b51..2ca5f03242 100644 --- a/src/common/displayport/src/dp_configcaps.cpp +++ b/src/common/displayport/src/dp_configcaps.cpp @@ -185,11 +185,21 @@ void DPCDHALImpl::parseAndReadCaps() // Set an invalid state here and make sure we REMEMBER we couldn't get the caps caps.revisionMajor = 0; dpcdOffline = true; + if (bVirtualSinkDpcdFallback) + { + // + // Forced/sink-less connector (EDID override, no AUX): fall back to + // fake caps so discovery can proceed and create a device. + // + populateFakeDpcd(); + caps.revisionMinor = 0x4; + } return; } // reset the faked dpcd flag since real LT should be possible now. dpcdOffline = false; + bVirtualSinkDpcdFallback = false; // reset edp revision to 0 caps.eDpRevision = 0; @@ -634,6 +644,14 @@ bool DPCDHALImpl::getSDPExtnForColorimetry() { bool bSDPExtnForColorimetry = false; NvU8 byte = 0; + if (dpcdOffline && bVirtualSinkDpcdFallback) + { + // + // 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)) @@ -3180,4 +3198,3 @@ DPCDHAL * DisplayPort::MakeDPCDHAL(AuxBus * bus, Timer * timer, MainLink * main return new DPCDHALImpl(bus, timer); } } - diff --git a/src/common/displayport/src/dp_connectorimpl.cpp b/src/common/displayport/src/dp_connectorimpl.cpp index be1cdfba5b..a0aaf865bb 100644 --- a/src/common/displayport/src/dp_connectorimpl.cpp +++ b/src/common/displayport/src/dp_connectorimpl.cpp @@ -7348,6 +7348,7 @@ void ConnectorImpl::notifyLongPulse(bool statusConnected) { NvU32 muxState = 0; NV_DPTRACE_INFO(HOTPLUG, statusConnected, connectorActive, previousPlugged); + hal->setVirtualSinkDpcdFallback(false); if (!connectorActive) { @@ -7427,6 +7428,18 @@ void ConnectorImpl::notifyLongPulse(bool statusConnected) this->notifyLongPulseInternal(statusConnected); } +void ConnectorImpl::notifyVirtualSinkLongPulse(bool statusConnected) +{ + if (!connectorActive) + { + DP_PRINTF(DP_ERROR, "DP> Got a virtual-sink long pulse before any connector is active!!"); + return; + } + + hal->setVirtualSinkDpcdFallback(statusConnected); + this->notifyLongPulseInternal(statusConnected); +} + /*! * @brief Compute the max BW required across all devices and try to allocate that BW * @@ -9313,4 +9326,3 @@ void ConnectorImpl::ensureMstNodesPoweredUp(Group * target) } } } - diff --git a/src/common/displayport/src/dp_deviceimpl.cpp b/src/common/displayport/src/dp_deviceimpl.cpp index 9d1313e5c0..d5b32bebe1 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->isVirtualSinkDpcdFallback()) + { + // + // 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,12 @@ bool DeviceImpl::getFECSupport() bFECSupported = this->bandwidth.enum_path.bPathFECCapable; } + else if (hal->isVirtualSinkDpcdFallback()) + { + // 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 +2575,30 @@ bool DeviceImpl::readAndParseDSCCaps() if(AuxBus::success != this->getDpcdData(NV_DPCD14_DSC_SUPPORT, &rawDscCaps[0], sizeof(rawDscCaps), &sizeCompleted, &nakReason)) { + if (hal->isVirtualSinkDpcdFallback()) + { + // + // 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 27304b9152..2bcd925fef 100644 --- a/src/nvidia-modeset/include/dp/nvdp-connector.h +++ b/src/nvidia-modeset/include/dp/nvdp-connector.h @@ -35,8 +35,13 @@ NVDPLibConnectorPtr nvDPCreateConnector(NVConnectorEvoPtr pConnectorEvo); void nvDPNotifyLongPulse(NVConnectorEvoPtr pConnectorEvo, NvBool connected); +void nvDPNotifyVirtualSinkLongPulse(NVConnectorEvoPtr pConnectorEvo, + NvBool connected); + 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 61cb523b18..552f6f570d 100644 --- a/src/nvidia-modeset/src/dp/nvdp-connector.cpp +++ b/src/nvidia-modeset/src/dp/nvdp-connector.cpp @@ -121,6 +121,22 @@ void nvDPNotifyLongPulse(NVConnectorEvoPtr pConnectorEvo, } +void nvDPNotifyVirtualSinkLongPulse(NVConnectorEvoPtr pConnectorEvo, + NvBool connected) +{ + NVDPLibConnectorPtr pNVDpLibConnector = pConnectorEvo->pDpLibConnector; + DisplayPort::Connector *c = pNVDpLibConnector->connector; + + pNVDpLibConnector->plugged = connected; + c->notifyVirtualSinkLongPulse(connected); +} + +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 7fc92fcfd7..bb5e45b646 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 + * virtual-sink plug so DPLib performs discovery with fake DPCD + * caps scoped to this explicit force-connected path. + */ + nvDPNotifyVirtualSinkLongPulse(pConnectorEvo, TRUE); + } connectedList = oneDpyIdList; } else if (pRequest->forceDisconnected) { connectedList = nvEmptyDpyIdList();