mirror of
https://github.com/NVIDIA/open-gpu-kernel-modules.git
synced 2026-02-05 23:59:59 +00:00
528 lines
18 KiB
C++
528 lines
18 KiB
C++
/*
|
|
* SPDX-FileCopyrightText: Copyright (c) 1993-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.
|
|
*/
|
|
|
|
/******************************* DisplayPort*********************************\
|
|
* *
|
|
* Module: dp_connector.cpp *
|
|
* *
|
|
\***************************************************************************/
|
|
#ifndef INCLUDED_DP_DEVICEIMPL_H
|
|
#define INCLUDED_DP_DEVICEIMPL_H
|
|
|
|
#include "dp_connector.h"
|
|
#include "dp_internal.h"
|
|
#include "dp_edid.h"
|
|
#include "dp_list.h"
|
|
#include "dp_auxdefs.h"
|
|
#include "dp_vrr.h"
|
|
|
|
namespace DisplayPort
|
|
{
|
|
#define PREDEFINED_DSC_MST_BPPX16 160;
|
|
#define HDCP_BCAPS_DDC_OFFSET 0x40
|
|
#define HDCP_BCAPS_DDC_EN_BIT 0x80
|
|
#define HDCP_BCAPS_DP_EN_BIT 0x01
|
|
#define HDCP_I2C_CLIENT_ADDR 0x74
|
|
|
|
struct GroupImpl;
|
|
struct ConnectorImpl;
|
|
class DeviceHDCPDetection;
|
|
class VrrEnablement;
|
|
|
|
struct DeviceImpl : public Device,
|
|
public AuxBus,
|
|
public ListElement
|
|
{
|
|
//
|
|
// Shadow state: This is the last state delivered to DD.
|
|
// see the ConnectorImpl::fireEvents() function for handling.
|
|
//
|
|
// State is double buffered to allow for allow announces
|
|
// to happen at the end of the state updates. We assume
|
|
// the DD can call any Connector API in response to the
|
|
// event.
|
|
//
|
|
struct Shadow
|
|
{
|
|
bool plugged;
|
|
bool zombie;
|
|
bool cableOk;
|
|
bool mustDisconnect;
|
|
bool hdcpCapDone;
|
|
LinkConfiguration highestAssessedLC;
|
|
} shadow;
|
|
|
|
struct BandWidth
|
|
{
|
|
struct _Enum_Path
|
|
{
|
|
unsigned total, free;
|
|
bool bPathFECCapable;
|
|
bool dataValid; // Is the cache valid?
|
|
} enum_path;
|
|
|
|
struct Compound_Query_State
|
|
{
|
|
unsigned totalTimeSlots; // Total timeslots available for allocation across this node
|
|
|
|
unsigned timeslots_used_by_query; // Timeslots accounted for.
|
|
|
|
unsigned bandwidthAllocatedForIndex; // Compound query is compromised of several
|
|
// qeuery attaches. These query attaches
|
|
// may have more than one device associated.
|
|
// this mask keeps track of which queryAttach's
|
|
// have already had the stream "rounted" past
|
|
// this node.
|
|
} compound_query_state;
|
|
|
|
LinkConfiguration lastHopLinkConfig; // inferred from enum_path.total
|
|
|
|
} bandwidth;
|
|
|
|
enum rawEprState
|
|
{
|
|
software,
|
|
hardware
|
|
};
|
|
|
|
void resetCacheInferredLink();
|
|
LinkConfiguration * inferLeafLink(unsigned * totalLinkSlots);
|
|
|
|
|
|
DeviceImpl * parent; // Upstream parent device
|
|
DeviceImpl * children[16];
|
|
PortMap portMap;
|
|
|
|
Edid rawEDID;
|
|
Edid processedEdid;
|
|
Edid ddcEdid;
|
|
DPCDHAL * hal;
|
|
GroupImpl * activeGroup;
|
|
ConnectorImpl * connector;
|
|
ConnectorType connectorType;
|
|
Address address;
|
|
GUID guid;
|
|
GUID guid2;
|
|
bool bVirtualPeerDevice;
|
|
NvU8 peerDevice;
|
|
NvU8 dpcdRevisionMajor;
|
|
NvU8 dpcdRevisionMinor;
|
|
bool multistream;
|
|
bool videoSink, audioSink;
|
|
bool plugged;
|
|
|
|
|
|
AuxRetry friendlyAux;
|
|
bool payloadAllocated; // did the allocate payload go through?
|
|
|
|
unsigned char BCAPS[HDCP_BCAPS_SIZE]; // Hdcp1.x bCaps raw data
|
|
unsigned char BKSV[HDCP_KSV_SIZE]; // Hdcp1.x bKsv raw data
|
|
unsigned char nvBCaps[HDCP_BCAPS_SIZE]; // NV generic HDCP BCAPS including 1.x, 2.2, ...
|
|
NvU64 maxTmdsClkRate;
|
|
|
|
|
|
bool isPendingNewDevice();
|
|
bool isPendingLostDevice();
|
|
bool isPendingZombie();
|
|
bool isPendingCableOk();
|
|
bool isPendingBandwidthChange();
|
|
bool isPendingHDCPCapDone();
|
|
|
|
TriState isHDCPCap;
|
|
bool isDeviceHDCPDetectionAlive;
|
|
DeviceHDCPDetection * deviceHDCPDetection;
|
|
|
|
PCONCaps pconCaps;
|
|
|
|
// this flag signifies that the compliance device has requested EDID read test and may follow
|
|
// hidden and lazy zombie policy.
|
|
bool complianceDeviceEdidReadTest;
|
|
|
|
bool lazyExitNow;
|
|
|
|
// VRR Enablement structure
|
|
VrrEnablement *vrrEnablement;
|
|
|
|
// DSC fields
|
|
NvU8 rawDscCaps[16];
|
|
DscCaps dscCaps;
|
|
|
|
// Panel replay Caps
|
|
PanelReplayCaps prCaps;
|
|
|
|
bool bIsFakedMuxDevice;
|
|
bool bIsPreviouslyFakedMuxDevice;
|
|
bool bisMarkedForDeletion;
|
|
bool bIgnoreMsaCap;
|
|
bool bIgnoreMsaCapCached;
|
|
|
|
//
|
|
// Device doing the DSC decompression for this device. This could be device itself
|
|
// or its parent
|
|
//
|
|
DeviceImpl* devDoingDscDecompression;
|
|
//
|
|
// If DSC stream can be sent to this device or not. Either device itself or it's
|
|
// parent can do DSC decompression
|
|
//
|
|
bool bDSCPossible;
|
|
|
|
bool bFECSupported;
|
|
bool bFECUncorrectedSupported;
|
|
bool bFECCorrectedSupported;
|
|
bool bFECBitSupported;
|
|
bool bFECParityBlockSupported;
|
|
bool bFECParitySupported;
|
|
|
|
TriState bSdpExtCapable;
|
|
bool bMSAOverMSTCapable;
|
|
bool bDscPassThroughColorFormatWar;
|
|
|
|
DeviceImpl(DPCDHAL * hal, ConnectorImpl * connector, DeviceImpl * parent);
|
|
~DeviceImpl();
|
|
|
|
virtual bool isCableOk();
|
|
virtual bool isLogical();
|
|
virtual bool isZombie();
|
|
|
|
virtual unsigned getEDIDSize() const;
|
|
virtual bool getEDID(char * buffer, unsigned size) const;
|
|
virtual unsigned getRawEDIDSize() const;
|
|
virtual bool getRawEDID(char * buffer, unsigned size) const;
|
|
|
|
virtual bool getPCONCaps(PCONCaps *pPCONCaps);
|
|
|
|
virtual Group * getOwningGroup()
|
|
{
|
|
return (Group *)activeGroup;
|
|
}
|
|
|
|
bool isActive();
|
|
|
|
void applyOUIOverrides();
|
|
|
|
virtual Device * getParent()
|
|
{
|
|
return parent;
|
|
}
|
|
|
|
virtual Device * getChild(unsigned portNumber)
|
|
{
|
|
return children[portNumber];
|
|
}
|
|
|
|
virtual bool isMultistream() // Sink supports multistream, remember we can have 1.1 targets
|
|
{
|
|
return address.size() != 0;
|
|
}
|
|
|
|
virtual bool isNativeDPCD()
|
|
{
|
|
return (address.size() < 2);
|
|
}
|
|
|
|
virtual bool isVideoSink()
|
|
{
|
|
return videoSink;
|
|
}
|
|
|
|
virtual bool isAudioSink()
|
|
{
|
|
return audioSink;
|
|
}
|
|
|
|
virtual bool isLoop()
|
|
{
|
|
DP_LOG(("isLoop implementation is pending (bug 791059)"));
|
|
return false;
|
|
}
|
|
|
|
virtual bool isRedundant()
|
|
{
|
|
DP_LOG(("isRedundant implementation is pending (bug 791059)"));
|
|
return false;
|
|
}
|
|
|
|
virtual bool isMustDisconnect();
|
|
|
|
virtual bool isPlugged()
|
|
{
|
|
return plugged;
|
|
}
|
|
|
|
virtual Address getTopologyAddress() const
|
|
{
|
|
return address;
|
|
}
|
|
|
|
virtual ConnectorType getConnectorType()
|
|
{
|
|
return connectorType;
|
|
}
|
|
|
|
virtual bool isFallbackEdid()
|
|
{
|
|
return this->processedEdid.isFallbackEdid();
|
|
}
|
|
|
|
virtual GUID getGUID() const
|
|
{
|
|
return guid;
|
|
}
|
|
|
|
virtual PortMap getPortMap() const
|
|
{
|
|
return portMap;
|
|
}
|
|
|
|
virtual TriState hdcpAvailableHop();
|
|
virtual TriState hdcpAvailable();
|
|
|
|
virtual bool isMSAOverMSTCapable()
|
|
{
|
|
return bMSAOverMSTCapable;
|
|
}
|
|
|
|
virtual bool isFakedMuxDevice();
|
|
virtual bool isPreviouslyFakedMuxDevice();
|
|
|
|
bool bypassDpcdPowerOff()
|
|
{
|
|
return processedEdid.WARFlags.disableDpcdPowerOff;
|
|
}
|
|
|
|
bool powerOnMonitorBeforeLt()
|
|
{
|
|
return processedEdid.WARFlags.powerOnBeforeLt;
|
|
}
|
|
|
|
bool forceMaxLinkConfig()
|
|
{
|
|
return processedEdid.WARFlags.forceMaxLinkConfig;
|
|
}
|
|
|
|
bool skipRedundantLt()
|
|
{
|
|
return processedEdid.WARFlags.skipRedundantLt;
|
|
}
|
|
|
|
bool ignoreRedundantHotplug()
|
|
{
|
|
return processedEdid.WARFlags.ignoreRedundantHotplug;
|
|
}
|
|
|
|
bool isOptimalLinkConfigOverridden()
|
|
{
|
|
return processedEdid.WARFlags.overrideOptimalLinkCfg;
|
|
}
|
|
|
|
// Apply DPCD overrides if required
|
|
void dpcdOverrides();
|
|
|
|
bool getDpcdRevision(unsigned * major, unsigned * minor)
|
|
{
|
|
if (!major || !minor)
|
|
{
|
|
DP_ASSERT(0 && "Null pointers passed in.");
|
|
return false;
|
|
}
|
|
|
|
*major = this->dpcdRevisionMajor;
|
|
*minor = this->dpcdRevisionMinor;
|
|
return true;
|
|
}
|
|
|
|
bool getIgnoreMSACap();
|
|
|
|
AuxRetry::status setIgnoreMSAEnable(bool msaTimingParamIgnoreEn);
|
|
|
|
bool isVirtualPeerDevice()
|
|
{
|
|
return bVirtualPeerDevice;
|
|
}
|
|
|
|
bool isBranchDevice()
|
|
{
|
|
return !isVideoSink() && !isAudioSink();
|
|
}
|
|
|
|
bool isAtLeastVersion(unsigned major, unsigned minor)
|
|
{
|
|
if (dpcdRevisionMajor > major)
|
|
return true;
|
|
|
|
if (dpcdRevisionMajor < major)
|
|
return false;
|
|
|
|
return dpcdRevisionMinor >= minor;
|
|
}
|
|
|
|
virtual void queryGUID2();
|
|
|
|
virtual bool getSDPExtnForColorimetrySupported();
|
|
|
|
virtual bool getPanelFwRevision(NvU16 *revision);
|
|
|
|
virtual bool isPowerSuspended();
|
|
|
|
virtual void setPanelPowerParams(bool bSinkPowerStateD0, bool bPanelPowerStateOn);
|
|
|
|
virtual status transaction(Action action, Type type, int address,
|
|
NvU8 * buffer, unsigned sizeRequested,
|
|
unsigned * sizeCompleted,
|
|
unsigned *pNakReason= NULL,
|
|
NvU8 offset= 0, NvU8 nWriteTransactions= 0);
|
|
virtual unsigned transactionSize();
|
|
// default behaviour is querying first three registers for every lane --> flags = 0x7
|
|
virtual status fecTransaction(NvU8 *fecStatus, NvU16 **fecErrorCount, NvU32 flags = NV_DP_FEC_FLAGS_SELECT_ALL);
|
|
virtual AuxBus * getRawAuxChannel() { return this; }
|
|
virtual AuxRetry * getAuxChannel() { return &friendlyAux; }
|
|
virtual AuxBus::status getDpcdData(unsigned offset, NvU8 * buffer,
|
|
unsigned sizeRequested,
|
|
unsigned * sizeCompleted,
|
|
unsigned * pNakReason=NULL);
|
|
virtual AuxBus::status setDpcdData(unsigned offset, NvU8 * buffer,
|
|
unsigned sizeRequested,
|
|
unsigned * sizeCompleted,
|
|
unsigned * pNakReason=NULL);
|
|
virtual AuxBus::status queryFecData(NvU8 *fecStatus, NvU16 **fecErrorCount, NvU32 flags);
|
|
|
|
virtual DscCaps getDscCaps();
|
|
|
|
//
|
|
// This function returns the device itself or its parent device that is doing
|
|
// DSC decompression for it.
|
|
//
|
|
virtual Device* getDevDoingDscDecompression();
|
|
virtual void markDeviceForDeletion() {bisMarkedForDeletion = true;};
|
|
virtual bool isMarkedForDeletion() {return bisMarkedForDeletion;};
|
|
virtual bool getRawDscCaps(NvU8 *buffer, NvU32 bufferSize);
|
|
|
|
virtual AuxBus::status dscCrcControl(NvBool bEnable, gpuDscCrc *dataGpu, sinkDscCrc *dataSink);
|
|
|
|
//
|
|
// Parameter bForceMot in both getI2cData and setI2cData is used to forfully set
|
|
// the MOT bit. It is needed for some special cases where the MOT bit shouldn't
|
|
// be set but some customers need it to please their monitors.
|
|
//
|
|
virtual bool getI2cData(unsigned offset, NvU8 * buffer, unsigned sizeRequested, unsigned * sizeCompleted, bool bForceMot = false);
|
|
virtual bool setI2cData(unsigned offset, NvU8 * buffer, unsigned sizeRequested, unsigned * sizeCompleted, bool bForceMot = false);
|
|
virtual bool getRawEpr(unsigned * totalEpr, unsigned * freeEpr, rawEprState eprState);
|
|
|
|
void switchToComplianceFallback();
|
|
|
|
// VRR Display Enablement Functions
|
|
bool startVrrEnablement(void);
|
|
void resetVrrEnablement(void);
|
|
bool isVrrMonitorEnabled(void);
|
|
bool isVrrDriverEnabled(void);
|
|
|
|
// Panel replay related functions
|
|
bool isPanelReplaySupported(void);
|
|
void getPanelReplayCaps(void);
|
|
bool setPanelReplayConfig(panelReplayConfig prcfg);
|
|
bool getPanelReplayStatus(PanelReplayStatus *pPrStatus);
|
|
|
|
NvBool getDSCSupport();
|
|
bool getFECSupport();
|
|
NvBool isDSCPassThroughSupported();
|
|
NvBool isDSCSupported();
|
|
NvBool isDSCPossible();
|
|
bool isFECSupported();
|
|
bool readAndParseDSCCaps();
|
|
bool readAndParseBranchSpecificDSCCaps();
|
|
bool parseDscCaps(const NvU8 *buffer, NvU32 bufferSize);
|
|
bool parseBranchSpecificDscCaps(const NvU8 *buffer, NvU32 bufferSize);
|
|
bool setDscEnable(bool enable);
|
|
bool setDscEnableDPToHDMIPCON(bool bDscEnable, bool bEnablePassThroughForPCON);
|
|
bool getDscEnable(bool *pEnable);
|
|
unsigned getDscVersionMajor();
|
|
unsigned getDscVersionMinor();
|
|
unsigned getDscRcBufferSize();
|
|
unsigned getDscRcBufferBlockSize();
|
|
unsigned getDscMaxSlicesPerSink();
|
|
unsigned getDscLineBufferBitDepth();
|
|
NvBool isDscBlockPredictionSupported();
|
|
unsigned getDscMaxBitsPerPixel();
|
|
NvBool isDscRgbSupported();
|
|
NvBool isDscYCbCr444Supported();
|
|
NvBool isDscYCbCrSimple422Supported();
|
|
NvBool isDscYCbCr422NativeSupported();
|
|
NvBool isDscYCbCr420NativeSupported();
|
|
unsigned getDscPeakThroughputMode0();
|
|
unsigned getDscPeakThroughputModel();
|
|
unsigned getDscMaxSliceWidth();
|
|
unsigned getDscDecoderColorDepthSupportMask();
|
|
void setDscDecompressionDevice(bool bDscCapBasedOnParent);
|
|
};
|
|
class DeviceHDCPDetection : public Object, MessageManager::Message::MessageEventSink, Timer::TimerCallback
|
|
{
|
|
DeviceImpl* parent;
|
|
RemoteDpcdReadMessage remoteBKSVReadMessage;
|
|
RemoteDpcdReadMessage remoteBCapsReadMessage;
|
|
RemoteDpcdReadMessage remote22BCapsReadMessage;
|
|
MessageManager * messageManager; // For transmit and receive
|
|
Timer * timer;
|
|
bool bksvReadCompleted;
|
|
bool bCapsReadCompleted;
|
|
bool isValidBKSV;
|
|
bool isBCapsHDCP;
|
|
unsigned retriesRemoteBKSVReadMessage;
|
|
unsigned retriesRemoteBCapsReadMessage;
|
|
unsigned retriesRemote22BCapsReadMessage;
|
|
bool retryRemoteBKSVReadMessage;
|
|
bool retryRemoteBCapsReadMessage;
|
|
bool retryRemote22BCapsReadMessage;
|
|
bool bBKSVReadMessagePending;
|
|
bool bBCapsReadMessagePending;
|
|
|
|
public:
|
|
|
|
DeviceHDCPDetection(DeviceImpl * parent, MessageManager * messageManager, Timer * timer)
|
|
: bksvReadCompleted(false),bCapsReadCompleted(false),isValidBKSV(false),
|
|
isBCapsHDCP(false), retriesRemoteBKSVReadMessage(0), retriesRemoteBCapsReadMessage(0),
|
|
retriesRemote22BCapsReadMessage(0), retryRemoteBKSVReadMessage(false),
|
|
retryRemoteBCapsReadMessage(false), retryRemote22BCapsReadMessage(false),
|
|
bBKSVReadMessagePending(false), bBCapsReadMessagePending(false)
|
|
|
|
{
|
|
this->parent = parent;
|
|
this->messageManager = messageManager;
|
|
this->timer = timer;
|
|
}
|
|
|
|
~DeviceHDCPDetection();
|
|
void expired(const void * tag);
|
|
void start();
|
|
void waivePendingHDCPCapDoneNotification();
|
|
|
|
bool hdcpValidateKsv(const NvU8 *ksv, NvU32 Size);
|
|
void handleRemoteDpcdReadDownReply(MessageManager::Message * from);
|
|
void messageFailed(MessageManager::Message * from, NakData * nakData);
|
|
void messageCompleted(MessageManager::Message * from);
|
|
};
|
|
}
|
|
|
|
#endif //INCLUDED_DP_DEVICEIMPL_H
|
|
|