From 1c23e6bcf1fbf14997e2458d043b359637ef20f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Tue, 3 May 2022 16:01:58 +0200 Subject: [PATCH] intel_extreme: leverage VBT device type for internal panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 Reviewed-by: Jérôme Duval --- .../graphics/intel_extreme/intel_extreme.h | 25 ++++++++++ .../accelerants/intel_extreme/Ports.cpp | 49 +++++++++++++++---- src/add-ons/accelerants/intel_extreme/Ports.h | 1 + 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 4a9dbd4a1d..31f732ea07 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -289,6 +289,22 @@ struct ring_buffer { struct child_device_config { uint16 handle; 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]; uint16 addin_offset; uint8 dvo_port; @@ -1112,6 +1128,15 @@ struct intel_brightness_legacy { (_DPA_AUX_CH_CTL + (_DPB_AUX_CH_CTL - _DPA_AUX_CH_CTL) * aux) #define DP_AUX_CH_DATA(aux, i) \ (_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_DONE (1 << 30) diff --git a/src/add-ons/accelerants/intel_extreme/Ports.cpp b/src/add-ons/accelerants/intel_extreme/Ports.cpp index 2971e44fe7..8d3607dfc9 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.cpp +++ b/src/add-ons/accelerants/intel_extreme/Ports.cpp @@ -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 @@ -1224,7 +1235,8 @@ DisplayPort::IsConnected() TRACE("%s: %s link detected\n", __func__, PortName()); // 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) { TRACE("%s: Laptop. Using VESA edid info\n", __func__); memcpy(&fEDIDInfo, &gInfo->shared_info->vesa_edid_info, @@ -1260,7 +1272,7 @@ DigitalDisplayInterface::SetupI2c(i2c_bus *bus) CALLED(); 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()) return Port::SetupI2c(bus); } @@ -1510,11 +1522,16 @@ DigitalDisplayInterface::_DpAuxTransfer(uint8* transmitBuffer, uint8 transmitSiz { addr_t channelControl; addr_t channelData[5]; - if (gInfo->shared_info->device_type.Generation() >= 9) { - // assume AUX channel 0 - channelControl = DP_AUX_CH_CTL(_DpAuxChannel()); + aux_channel channel = _DpAuxChannel(); + if (gInfo->shared_info->device_type.Generation() >= 9 + || (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++) - 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 { ERROR("DigitalDisplayInterface::_DpAuxTransfer() unknown register config\n"); 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 | (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); + } 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; @@ -1863,7 +1889,8 @@ DisplayPort::SetDisplayMode(display_mode* target, uint32 colorMode) } else { display_timing hardwareTarget = target->timing; 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 // native video mode, and let the panel fitter do the scaling. // 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; - if (gInfo->shared_info->device_type.Generation() >= 9 && deviceConfigCount > 0) { + if (gInfo->shared_info->device_type.Generation() >= 6 && deviceConfigCount > 0) { // check VBT mapping if (!_IsPortInVBT()) { 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) 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); TRACE("%s: PIPE_DDI_FUNC_CTL_EDP: 0x%" B_PRIx32 "\n", __func__, pipeState); if (!(pipeState & PIPE_DDI_FUNC_CTL_ENABLE)) { @@ -2426,7 +2454,8 @@ DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode) display_timing hardwareTarget = target->timing; 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 // native video mode, and let the panel fitter do the scaling. diff --git a/src/add-ons/accelerants/intel_extreme/Ports.h b/src/add-ons/accelerants/intel_extreme/Ports.h index f23de95384..b7871a976b 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.h +++ b/src/add-ons/accelerants/intel_extreme/Ports.h @@ -77,6 +77,7 @@ static status_t _SetI2CSignals(void* cookie, int clock, int data); bool _IsPortInVBT(uint32* foundIndex = NULL); bool _IsDisplayPortInVBT(); + bool _IsInternalPanelPort(); display_mode fCurrentMode; Pipe* fPipe;