intel_extreme: probe DP AUX or/and DDC on DDI ports

* the VBT tells whether DDI ports can have both DP and HDMI/DVI as outputs.
* tested on Dell Optiplex 9020 Gen7/Haswell with an HDMI/DP adapter on a DP connector.
* avoids enabling a down DDI port when an EDID is found: the display isn't setup by the BIOS.

Change-Id: I69487a2fcb74899d7c22d04e955e776b0e739151
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5317
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
This commit is contained in:
Jérôme Duval 2022-05-16 20:16:57 +02:00
parent 07d5dba065
commit fe3aff01c0
2 changed files with 54 additions and 13 deletions

View File

@ -234,6 +234,13 @@ Port::GetEDID(edid1_info* edid, bool forceRead)
if (fEDIDState == B_OK) {
TRACE("%s: found EDID information!\n", PortName());
edid_dump(&fEDIDInfo);
} else if (SetupI2cFallback(&bus) == B_OK) {
fEDIDState = ddc2_read_edid1(&bus, &fEDIDInfo, NULL, NULL);
if (fEDIDState == B_OK) {
TRACE("%s: found EDID information!\n", PortName());
edid_dump(&fEDIDInfo);
}
}
}
@ -270,6 +277,13 @@ Port::SetupI2c(i2c_bus *bus)
}
status_t
Port::SetupI2cFallback(i2c_bus *bus)
{
return B_ERROR;
}
status_t
Port::GetPLLLimits(pll_limits& limits)
{
@ -453,7 +467,19 @@ Port::_IsDisplayPortInVBT()
if (!_IsPortInVBT(&foundIndex))
return false;
child_device_config& config = gInfo->shared_info->device_configs[foundIndex];
return config.aux_channel > 0;
return config.aux_channel > 0 && (config.device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT) != 0;
}
bool
Port::_IsHdmiInVBT()
{
uint32 foundIndex = 0;
if (!_IsPortInVBT(&foundIndex))
return false;
child_device_config& config = gInfo->shared_info->device_configs[foundIndex];
return config.ddc_pin > 0 && ((config.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0
|| (config.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING) != 0);
}
@ -607,7 +633,7 @@ Port::_DpAuxSendReceiveHook(const struct i2c_bus *bus, uint32 slaveAddress,
const uint8 *writeBuffer, size_t writeLength, uint8 *readBuffer, size_t readLength)
{
CALLED();
DigitalDisplayInterface* port = (DigitalDisplayInterface*)bus->cookie;
Port* port = (Port*)bus->cookie;
return port->_DpAuxSendReceive(slaveAddress, writeBuffer, writeLength, readBuffer, readLength);
}
@ -693,9 +719,12 @@ Port::_DpAuxTransfer(dp_aux_msg* message)
else if (result < B_OK)
return result;
switch(message->reply & DP_AUX_NATIVE_REPLY_MASK) {
switch (message->reply & DP_AUX_NATIVE_REPLY_MASK) {
case DP_AUX_NATIVE_REPLY_ACK:
return B_OK;
case DP_AUX_NATIVE_REPLY_NACK:
TRACE("%s: aux native reply nack\n", __func__);
return B_IO_ERROR;
case DP_AUX_NATIVE_REPLY_DEFER:
TRACE("%s: aux reply defer received. Snoozing.\n", __func__);
snooze(400);
@ -2181,6 +2210,21 @@ DigitalDisplayInterface::SetupI2c(i2c_bus *bus)
}
status_t
DigitalDisplayInterface::SetupI2cFallback(i2c_bus *bus)
{
CALLED();
const uint32 deviceConfigCount = gInfo->shared_info->device_config_count;
if (gInfo->shared_info->device_type.Generation() >= 6 && deviceConfigCount > 0
&& _IsDisplayPortInVBT() && _IsHdmiInVBT()) {
return Port::SetupI2c(bus);
}
return B_ERROR;
}
bool
DigitalDisplayInterface::IsConnected()
{
@ -2310,17 +2354,11 @@ DigitalDisplayInterface::IsConnected()
break;
}
pipeState = read32(pipeReg);
if (!(pipeState & PIPE_DDI_FUNC_CTL_ENABLE)) {
TRACE("%s: Connected but port down: enabling port on pipe nr %" B_PRIx32 "\n", __func__, pipeCnt + 1);
//fixme: turn on port and power
pipeState |= PIPE_DDI_FUNC_CTL_ENABLE;
pipeState &= ~PIPE_DDI_SELECT_MASK;
pipeState |= (((uint32)PortIndex()) - 1) << PIPE_DDI_SELECT_SHIFT;
//fixme: set mode to DVI mode for now (b26..24 = %001)
write32(pipeReg, pipeState);
TRACE("%s: PIPE_DDI_FUNC_CTL after: 0x%" B_PRIx32 "\n", __func__, read32(pipeReg));
return true;
if ((pipeState & PIPE_DDI_FUNC_CTL_ENABLE) == 0) {
TRACE("%s: Connected but port down\n", __func__);
return false;
}
return true;
}
TRACE("%s: No pipe available, ignoring connected screen\n", __func__);
}

View File

@ -60,6 +60,7 @@ virtual status_t Power(bool enabled);
virtual status_t GetEDID(edid1_info* edid,
bool forceRead = false);
virtual status_t SetupI2c(struct i2c_bus *bus);
virtual status_t SetupI2cFallback(struct i2c_bus *bus);
virtual status_t GetPLLLimits(pll_limits& limits);
@ -77,6 +78,7 @@ static status_t _SetI2CSignals(void* cookie, int clock,
int data);
bool _IsPortInVBT(uint32* foundIndex = NULL);
bool _IsDisplayPortInVBT();
bool _IsHdmiInVBT();
bool _IsEDPPort();
status_t _SetupDpAuxI2c(struct i2c_bus *bus);
@ -231,6 +233,7 @@ virtual status_t Power(bool enabled);
virtual status_t SetPipe(Pipe* pipe);
virtual status_t SetupI2c(i2c_bus *bus);
virtual status_t SetupI2cFallback(struct i2c_bus *bus);
virtual bool IsConnected();