intel_extreme: leverage VBT device type for internal panel

* also handle dp aux on PCH.
* tested on Gen7, should work from Gen6.

Change-Id: I8d99bcdc10c817e66441a6a644df490dd988a74d
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5290
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-03 16:01:58 +02:00
parent d98fcb7db6
commit 1c23e6bcf1
3 changed files with 65 additions and 10 deletions

View File

@ -289,6 +289,22 @@ struct ring_buffer {
struct child_device_config { struct child_device_config {
uint16 handle; uint16 handle;
uint16 device_type; uint16 device_type;
#define DEVICE_TYPE_ANALOG_OUTPUT (1 << 0)
#define DEVICE_TYPE_DIGITAL_OUTPUT (1 << 1)
#define DEVICE_TYPE_DISPLAYPORT_OUTPUT (1 << 2)
#define DEVICE_TYPE_VIDEO_SIGNALING (1 << 3)
#define DEVICE_TYPE_TMDS_DVI_SIGNALING (1 << 4)
#define DEVICE_TYPE_LVDS_SIGNALING (1 << 5)
#define DEVICE_TYPE_HIGH_SPEED_LINK (1 << 6)
#define DEVICE_TYPE_DUAL_CHANNEL (1 << 8)
#define DEVICE_TYPE_COMPOSITE_OUTPUT (1 << 9)
#define DEVICE_TYPE_MIPI_OUTPUT (1 << 10)
#define DEVICE_TYPE_NOT_HDMI_OUTPUT (1 << 11)
#define DEVICE_TYPE_INTERNAL_CONNECTOR (1 << 12)
#define DEVICE_TYPE_HOTPLUG_SIGNALING (1 << 13)
#define DEVICE_TYPE_POWER_MANAGEMENT (1 << 14)
#define DEVICE_TYPE_CLASS_EXTENSION (1 << 15)
uint8 device_id[10]; uint8 device_id[10];
uint16 addin_offset; uint16 addin_offset;
uint8 dvo_port; uint8 dvo_port;
@ -1112,6 +1128,15 @@ struct intel_brightness_legacy {
(_DPA_AUX_CH_CTL + (_DPB_AUX_CH_CTL - _DPA_AUX_CH_CTL) * aux) (_DPA_AUX_CH_CTL + (_DPB_AUX_CH_CTL - _DPA_AUX_CH_CTL) * aux)
#define DP_AUX_CH_DATA(aux, i) \ #define DP_AUX_CH_DATA(aux, i) \
(_DPA_AUX_CH_DATA1 + (_DPB_AUX_CH_DATA1 - _DPA_AUX_CH_DATA1) * aux + i * 4) (_DPA_AUX_CH_DATA1 + (_DPB_AUX_CH_DATA1 - _DPA_AUX_CH_DATA1) * aux + i * 4)
#define _PCH_DPB_AUX_CH_CTL (0x4110 | REGS_SOUTH_TRANSCODER_PORT)
#define _PCH_DPB_AUX_CH_DATA1 (0x4114 | REGS_SOUTH_TRANSCODER_PORT)
#define _PCH_DPC_AUX_CH_CTL (0x4210 | REGS_SOUTH_TRANSCODER_PORT)
#define _PCH_DPC_AUX_CH_DATA1 (0x4214 | REGS_SOUTH_TRANSCODER_PORT)
#define PCH_DP_AUX_CH_CTL(aux) \
(_PCH_DPB_AUX_CH_CTL + (_PCH_DPC_AUX_CH_CTL - _PCH_DPB_AUX_CH_CTL) * (aux - AUX_CH_B))
#define PCH_DP_AUX_CH_DATA(aux, i) \
(_PCH_DPB_AUX_CH_DATA1 + (_PCH_DPC_AUX_CH_DATA1 - _PCH_DPB_AUX_CH_DATA1) * (aux - AUX_CH_B) \
+ i * 4)
#define INTEL_DP_AUX_CTL_BUSY (1 << 31) #define INTEL_DP_AUX_CTL_BUSY (1 << 31)
#define INTEL_DP_AUX_CTL_DONE (1 << 30) #define INTEL_DP_AUX_CTL_DONE (1 << 30)

View File

@ -457,6 +457,17 @@ Port::_IsDisplayPortInVBT()
} }
bool
Port::_IsInternalPanelPort()
{
uint32 foundIndex = 0;
if (!_IsPortInVBT(&foundIndex))
return false;
child_device_config& config = gInfo->shared_info->device_configs[foundIndex];
return (config.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR) == DEVICE_TYPE_INTERNAL_CONNECTOR;
}
// #pragma mark - Analog Port // #pragma mark - Analog Port
@ -1224,7 +1235,8 @@ DisplayPort::IsConnected()
TRACE("%s: %s link detected\n", __func__, PortName()); TRACE("%s: %s link detected\n", __func__, PortName());
// On laptops we always have an internal panel.. (this is on the eDP port) // On laptops we always have an internal panel.. (this is on the eDP port)
if (gInfo->shared_info->device_type.IsMobile() && (PortIndex() == INTEL_PORT_A)) { if ((gInfo->shared_info->device_type.IsMobile() || _IsInternalPanelPort())
&& (PortIndex() == INTEL_PORT_A)) {
if (gInfo->shared_info->has_vesa_edid_info) { if (gInfo->shared_info->has_vesa_edid_info) {
TRACE("%s: Laptop. Using VESA edid info\n", __func__); TRACE("%s: Laptop. Using VESA edid info\n", __func__);
memcpy(&fEDIDInfo, &gInfo->shared_info->vesa_edid_info, memcpy(&fEDIDInfo, &gInfo->shared_info->vesa_edid_info,
@ -1260,7 +1272,7 @@ DigitalDisplayInterface::SetupI2c(i2c_bus *bus)
CALLED(); CALLED();
const uint32 deviceConfigCount = gInfo->shared_info->device_config_count; const uint32 deviceConfigCount = gInfo->shared_info->device_config_count;
if (gInfo->shared_info->device_type.Generation() >= 9 && deviceConfigCount > 0) { if (gInfo->shared_info->device_type.Generation() >= 6 && deviceConfigCount > 0) {
if (!_IsDisplayPortInVBT()) if (!_IsDisplayPortInVBT())
return Port::SetupI2c(bus); return Port::SetupI2c(bus);
} }
@ -1510,11 +1522,16 @@ DigitalDisplayInterface::_DpAuxTransfer(uint8* transmitBuffer, uint8 transmitSiz
{ {
addr_t channelControl; addr_t channelControl;
addr_t channelData[5]; addr_t channelData[5];
if (gInfo->shared_info->device_type.Generation() >= 9) { aux_channel channel = _DpAuxChannel();
// assume AUX channel 0 if (gInfo->shared_info->device_type.Generation() >= 9
channelControl = DP_AUX_CH_CTL(_DpAuxChannel()); || (gInfo->shared_info->pch_info != INTEL_PCH_NONE && channel == AUX_CH_A)) {
channelControl = DP_AUX_CH_CTL(channel);
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
channelData[i] = DP_AUX_CH_DATA(_DpAuxChannel(), i); channelData[i] = DP_AUX_CH_DATA(channel, i);
} else if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) {
channelControl = PCH_DP_AUX_CH_CTL(channel);
for (int i = 0; i < 5; i++)
channelData[i] = PCH_DP_AUX_CH_DATA(channel, i);
} else { } else {
ERROR("DigitalDisplayInterface::_DpAuxTransfer() unknown register config\n"); ERROR("DigitalDisplayInterface::_DpAuxTransfer() unknown register config\n");
return B_BUSY; return B_BUSY;
@ -1537,6 +1554,15 @@ DigitalDisplayInterface::_DpAuxTransfer(uint8* transmitBuffer, uint8 transmitSiz
| INTEL_DP_AUX_CTL_TIMEOUT_ERROR | INTEL_DP_AUX_CTL_TIMEOUT_1600us | INTEL_DP_AUX_CTL_RECEIVE_ERROR | INTEL_DP_AUX_CTL_TIMEOUT_ERROR | INTEL_DP_AUX_CTL_TIMEOUT_1600us | INTEL_DP_AUX_CTL_RECEIVE_ERROR
| (transmitSize << INTEL_DP_AUX_CTL_MSG_SIZE_SHIFT) | INTEL_DP_AUX_CTL_FW_SYNC_PULSE_SKL(32) | (transmitSize << INTEL_DP_AUX_CTL_MSG_SIZE_SHIFT) | INTEL_DP_AUX_CTL_FW_SYNC_PULSE_SKL(32)
| INTEL_DP_AUX_CTL_SYNC_PULSE_SKL(32); | INTEL_DP_AUX_CTL_SYNC_PULSE_SKL(32);
} else {
uint32 aux_clock_divider = 0xe1; // TODO: value for 450Mhz
uint32 timeout = INTEL_DP_AUX_CTL_TIMEOUT_400us;
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_BDW))
timeout = INTEL_DP_AUX_CTL_TIMEOUT_600us;
sendControl = INTEL_DP_AUX_CTL_BUSY | INTEL_DP_AUX_CTL_DONE | INTEL_DP_AUX_CTL_INTERRUPT
| INTEL_DP_AUX_CTL_TIMEOUT_ERROR | timeout | INTEL_DP_AUX_CTL_RECEIVE_ERROR
| (transmitSize << INTEL_DP_AUX_CTL_MSG_SIZE_SHIFT) | (3 << INTEL_DP_AUX_CTL_PRECHARGE_2US_SHIFT)
| (aux_clock_divider << INTEL_DP_AUX_CTL_BIT_CLOCK_2X_SHIFT);
} }
uint8 retry; uint8 retry;
@ -1863,7 +1889,8 @@ DisplayPort::SetDisplayMode(display_mode* target, uint32 colorMode)
} else { } else {
display_timing hardwareTarget = target->timing; display_timing hardwareTarget = target->timing;
bool needsScaling = false; bool needsScaling = false;
if ((PortIndex() == INTEL_PORT_A) && gInfo->shared_info->device_type.IsMobile()) { if ((PortIndex() == INTEL_PORT_A)
&& (gInfo->shared_info->device_type.IsMobile() || _IsInternalPanelPort())) {
// For internal panels, we may need to set the timings according to the panel // For internal panels, we may need to set the timings according to the panel
// native video mode, and let the panel fitter do the scaling. // native video mode, and let the panel fitter do the scaling.
// note: upto/including generation 5 laptop panels are still LVDS types, handled elsewhere. // note: upto/including generation 5 laptop panels are still LVDS types, handled elsewhere.
@ -2175,7 +2202,7 @@ DigitalDisplayInterface::IsConnected()
} }
const uint32 deviceConfigCount = gInfo->shared_info->device_config_count; const uint32 deviceConfigCount = gInfo->shared_info->device_config_count;
if (gInfo->shared_info->device_type.Generation() >= 9 && deviceConfigCount > 0) { if (gInfo->shared_info->device_type.Generation() >= 6 && deviceConfigCount > 0) {
// check VBT mapping // check VBT mapping
if (!_IsPortInVBT()) { if (!_IsPortInVBT()) {
TRACE("%s: %s: port not found in VBT\n", __func__, PortName()); TRACE("%s: %s: port not found in VBT\n", __func__, PortName());
@ -2192,7 +2219,8 @@ DigitalDisplayInterface::IsConnected()
// On laptops we always have an internal panel.. (on the eDP port on DDI systems, fixed on eDP pipe) // On laptops we always have an internal panel.. (on the eDP port on DDI systems, fixed on eDP pipe)
uint32 pipeState = 0; uint32 pipeState = 0;
if (gInfo->shared_info->device_type.IsMobile() && (PortIndex() == INTEL_PORT_E)) { if ((gInfo->shared_info->device_type.IsMobile() || _IsInternalPanelPort())
&& (PortIndex() == INTEL_PORT_E)) {
pipeState = read32(PIPE_DDI_FUNC_CTL_EDP); pipeState = read32(PIPE_DDI_FUNC_CTL_EDP);
TRACE("%s: PIPE_DDI_FUNC_CTL_EDP: 0x%" B_PRIx32 "\n", __func__, pipeState); TRACE("%s: PIPE_DDI_FUNC_CTL_EDP: 0x%" B_PRIx32 "\n", __func__, pipeState);
if (!(pipeState & PIPE_DDI_FUNC_CTL_ENABLE)) { if (!(pipeState & PIPE_DDI_FUNC_CTL_ENABLE)) {
@ -2426,7 +2454,8 @@ DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode)
display_timing hardwareTarget = target->timing; display_timing hardwareTarget = target->timing;
bool needsScaling = false; bool needsScaling = false;
if ((PortIndex() == INTEL_PORT_E) && gInfo->shared_info->device_type.IsMobile()) { if ((PortIndex() == INTEL_PORT_E)
&& (gInfo->shared_info->device_type.IsMobile() || _IsInternalPanelPort())) {
// For internal panels, we may need to set the timings according to the panel // For internal panels, we may need to set the timings according to the panel
// native video mode, and let the panel fitter do the scaling. // native video mode, and let the panel fitter do the scaling.

View File

@ -77,6 +77,7 @@ static status_t _SetI2CSignals(void* cookie, int clock,
int data); int data);
bool _IsPortInVBT(uint32* foundIndex = NULL); bool _IsPortInVBT(uint32* foundIndex = NULL);
bool _IsDisplayPortInVBT(); bool _IsDisplayPortInVBT();
bool _IsInternalPanelPort();
display_mode fCurrentMode; display_mode fCurrentMode;
Pipe* fPipe; Pipe* fPipe;