From 456e6f33dd39a8000a5cfaabfb449ebaeb00119c Mon Sep 17 00:00:00 2001 From: Rudolf Cornelissen Date: Sun, 27 Feb 2022 22:25:04 +0100 Subject: [PATCH] intel_extreme: added more pipeC support, fixes for eDP on DDI systems --- .../graphics/intel_extreme/intel_extreme.h | 10 +- .../accelerants/intel_extreme/PanelFitter.cpp | 4 +- .../accelerants/intel_extreme/Pipes.cpp | 11 +-- src/add-ons/accelerants/intel_extreme/Pipes.h | 2 +- .../accelerants/intel_extreme/Ports.cpp | 99 +++++++++++++------ .../accelerants/intel_extreme/accelerant.cpp | 9 +- 6 files changed, 94 insertions(+), 41 deletions(-) diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 0b18fb73c6..e5f4e70d96 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -1087,8 +1087,14 @@ struct intel_free_graphics_memory { #define INTEL_GEN9_CLKGATE_DIS_4 (0x653c | REGS_NORTH_SHARED) #define BXT_GMBUSUNIT_CLK_GATE_DIS (1 << 14) -// gpu power wells -#define INTEL_PWR_WELL_CTL_2 (0x5404 | REGS_NORTH_SHARED) +// gpu power wells (confirmed skylake) +#define INTEL_PWR_WELL_CTL_1_BIOS (0x5400 | REGS_NORTH_SHARED) +#define INTEL_PWR_WELL_CTL_2_DRIVER (0x5404 | REGS_NORTH_SHARED) + +// gpu pll enable registers (confirmed skylake) +#define INTEL_WRPLL_CTL_1_DPLL2 (0x6040 | REGS_NORTH_SHARED) +#define INTEL_WRPLL_CTL_2_DPLL3 (0x6060 | REGS_NORTH_SHARED) +#define WRPLL_PLL_ENABLE (1 << 31) // TODO: on IronLake this is in the north shared block at 0x41000 #define INTEL_VGA_DISPLAY_CONTROL (0x1400 | REGS_NORTH_PLANE_CONTROL) diff --git a/src/add-ons/accelerants/intel_extreme/PanelFitter.cpp b/src/add-ons/accelerants/intel_extreme/PanelFitter.cpp index 5df2a3719d..4daf0787b9 100644 --- a/src/add-ons/accelerants/intel_extreme/PanelFitter.cpp +++ b/src/add-ons/accelerants/intel_extreme/PanelFitter.cpp @@ -57,7 +57,9 @@ PanelFitter::PanelFitter(pipe_index pipeIndex) TRACE("%s: this fitter is enabled by the BIOS\n", __func__); } } else { - TRACE("%s: this fitter is not setup by the BIOS\n", __func__); + TRACE("%s: this fitter is not setup by the BIOS: Enabling.\n", __func__); + fitCtl |= PANEL_FITTER_ENABLED; + write32(fRegisterBase + PCH_PANEL_FITTER_CONTROL, fitCtl); } } diff --git a/src/add-ons/accelerants/intel_extreme/Pipes.cpp b/src/add-ons/accelerants/intel_extreme/Pipes.cpp index ea8413d072..9459763d6c 100644 --- a/src/add-ons/accelerants/intel_extreme/Pipes.cpp +++ b/src/add-ons/accelerants/intel_extreme/Pipes.cpp @@ -68,21 +68,21 @@ Pipe::Pipe(pipe_index pipeIndex) fPipeOffset(0), fPlaneOffset(0) { - if (pipeIndex == INTEL_PIPE_B) { - fPlaneOffset = INTEL_PLANE_OFFSET; - } switch (pipeIndex) { case INTEL_PIPE_B: TRACE("Pipe B.\n"); fPipeOffset = 0x1000; + fPlaneOffset = INTEL_PLANE_OFFSET; break; case INTEL_PIPE_C: TRACE("Pipe C.\n"); fPipeOffset = 0x2000; + fPlaneOffset = INTEL_PLANE_OFFSET * 2; break; case INTEL_PIPE_D: TRACE("Pipe D.\n"); fPipeOffset = 0xf000; + //no fPlaneOffset.. break; default: TRACE("Pipe A.\n"); @@ -94,8 +94,7 @@ Pipe::Pipe(pipe_index pipeIndex) // SkyLake: FDI gone. No more northbridge video. if ((gInfo->shared_info->pch_info != INTEL_PCH_NONE) && (gInfo->shared_info->device_type.Generation() <= 8)) { - TRACE("%s: Pipe %s routed through FDI\n", __func__, - (pipeIndex == INTEL_PIPE_A) ? "A" : "B"); + TRACE("%s: Pipe is routed through FDI\n", __func__); // Program FDILink if PCH fFDILink = new(std::nothrow) FDILink(pipeIndex); @@ -561,7 +560,7 @@ Pipe::ConfigureClocksSKL(const skl_wrpll_params& wrpll_params, uint32 pixelClock *pllSel = (portSel & 0x6000) >> 13; break; default: - TRACE("No port selected!"); + TRACE("No port selected!\n"); return; } TRACE("PLL selected is %" B_PRIx32 "\n", *pllSel); diff --git a/src/add-ons/accelerants/intel_extreme/Pipes.h b/src/add-ons/accelerants/intel_extreme/Pipes.h index 1c361b99cf..de97a33309 100644 --- a/src/add-ons/accelerants/intel_extreme/Pipes.h +++ b/src/add-ons/accelerants/intel_extreme/Pipes.h @@ -19,7 +19,7 @@ #include "PanelFitter.h" -#define MAX_PIPES 2 +#define MAX_PIPES 4 // not all cards have this much though void program_pipe_color_modes(uint32 colorMode); diff --git a/src/add-ons/accelerants/intel_extreme/Ports.cpp b/src/add-ons/accelerants/intel_extreme/Ports.cpp index 65b05083eb..3dd90e8257 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.cpp +++ b/src/add-ons/accelerants/intel_extreme/Ports.cpp @@ -1721,41 +1721,24 @@ DigitalDisplayInterface::IsConnected() PortName(), fMaxLanes); // fetch EDID but determine 'in use' later (below) so we also catch screens that fail EDID - HasEDID(); + bool edidDetected = HasEDID(); - // scan all our pipes to find the one connected to the current port and check it's enabled + // On laptops we always have an internal panel.. (on the eDP port on DDI systems, fixed on eDP pipe) uint32 pipeState = 0; - for (uint32 pipeCnt = 0; pipeCnt < 4; pipeCnt++) { - switch (pipeCnt) { - case 0: - pipeState = read32(PIPE_DDI_FUNC_CTL_A); - break; - case 1: - pipeState = read32(PIPE_DDI_FUNC_CTL_B); - break; - case 2: - pipeState = read32(PIPE_DDI_FUNC_CTL_C); - break; - default: - pipeState = read32(PIPE_DDI_FUNC_CTL_EDP); - break; - } - - if ((((pipeState & PIPE_DDI_SELECT_MASK) >> PIPE_DDI_SELECT_SHIFT) + 1) == (uint32)PortIndex()) { - // See if the BIOS enabled our output as it indicates it's in use - if (pipeState & PIPE_DDI_FUNC_CTL_ENABLE) { - TRACE("%s: Connected\n", __func__); - return true; - } - } - } - - // On laptops we always have an internal panel.. (this is on the eDP port) if (gInfo->shared_info->device_type.IsMobile() && (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)) { + TRACE("%s: Laptop, but eDP port down: enabling port on pipe EDP\n", __func__); + //fixme: turn on port and power + write32(PIPE_DDI_FUNC_CTL_EDP, pipeState | PIPE_DDI_FUNC_CTL_ENABLE); + TRACE("%s: PIPE_DDI_FUNC_CTL_EDP after: 0x%" B_PRIx32 "\n", __func__, + read32(PIPE_DDI_FUNC_CTL_EDP)); + } + 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, - sizeof(edid1_info)); + memcpy(&fEDIDInfo, &gInfo->shared_info->vesa_edid_info, sizeof(edid1_info)); if (fEDIDState != B_OK) { fEDIDState = B_OK; // HasEDID now true @@ -1766,6 +1749,62 @@ DigitalDisplayInterface::IsConnected() TRACE("%s: Laptop. No EDID, but force enabled as we have a VBT\n", __func__); return true; } + //should not happen: + TRACE("%s: No (panel) type info found, assuming not connected\n", __func__); + return false; + } + + // scan all our non-eDP pipes to find the one connected to the current port and check it's enabled + for (uint32 pipeCnt = 0; pipeCnt < 3; pipeCnt++) { + switch (pipeCnt) { + case 1: + pipeState = read32(PIPE_DDI_FUNC_CTL_B); + break; + case 2: + pipeState = read32(PIPE_DDI_FUNC_CTL_C); + break; + default: + pipeState = read32(PIPE_DDI_FUNC_CTL_A); + break; + } + if ((((pipeState & PIPE_DDI_SELECT_MASK) >> PIPE_DDI_SELECT_SHIFT) + 1) == (uint32)PortIndex()) { + TRACE("%s: PIPE_DDI_FUNC_CTL nr %" B_PRIx32 ": 0x%" B_PRIx32 "\n", __func__, pipeCnt + 1, pipeState); + // See if the BIOS enabled our output as it indicates it's in use + if (pipeState & PIPE_DDI_FUNC_CTL_ENABLE) { + TRACE("%s: Connected\n", __func__); + return true; + } + } + } + + if (edidDetected) { + for (uint32 pipeCnt = 0; pipeCnt < 3; pipeCnt++) { + uint32 pipeReg = 0; + switch (pipeCnt) { + case 1: + pipeReg = PIPE_DDI_FUNC_CTL_B; + break; + case 2: + pipeReg = PIPE_DDI_FUNC_CTL_C; + break; + default: + pipeReg = PIPE_DDI_FUNC_CTL_A; + 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; + } + } + TRACE("%s: No pipe available, ignoring connected screen\n", __func__); } TRACE("%s: Not connected\n", __func__); diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.cpp b/src/add-ons/accelerants/intel_extreme/accelerant.cpp index 4e290f95a0..a6cbafa27e 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant.cpp +++ b/src/add-ons/accelerants/intel_extreme/accelerant.cpp @@ -143,7 +143,11 @@ init_common(int device, bool isClone) gInfo->pipe_count = 0; // Allocate all of our pipes - for (int i = 0; i < MAX_PIPES; i++) { + int pipeCnt = 2; + if (gInfo->shared_info->device_type.Generation() >= 7) + pipeCnt = 3; // some newer gens have even more.. + + for (int i = 0; i < pipeCnt; i++) { switch (i) { case 0: gInfo->pipes[i] = new(std::nothrow) Pipe(INTEL_PIPE_A); @@ -151,6 +155,9 @@ init_common(int device, bool isClone) case 1: gInfo->pipes[i] = new(std::nothrow) Pipe(INTEL_PIPE_B); break; + case 2: + gInfo->pipes[i] = new(std::nothrow) Pipe(INTEL_PIPE_C); + break; default: ERROR("%s: Unknown pipe %d\n", __func__, i); }