diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 75de2cfd43..524fc59937 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -847,7 +847,7 @@ struct intel_free_graphics_memory { #define SNB_DPLL_SEL (0x7000 | REGS_SOUTH_SHARED) -// i2c +// i2c bit banging interface #define INTEL_I2C_IO_A (0x5010 | REGS_SOUTH_SHARED) #define INTEL_I2C_IO_B (0x5014 | REGS_SOUTH_SHARED) #define INTEL_I2C_IO_C (0x5018 | REGS_SOUTH_SHARED) @@ -856,6 +856,9 @@ struct intel_free_graphics_memory { #define INTEL_I2C_IO_F (0x5024 | REGS_SOUTH_SHARED) #define INTEL_I2C_IO_G (0x5028 | REGS_SOUTH_SHARED) #define INTEL_I2C_IO_H (0x502c | REGS_SOUTH_SHARED) +// i2c hardware controller +#define INTEL_GMBUS0 (0x5100 | REGS_SOUTH_SHARED) +#define INTEL_GMBUS4 (0x5110 | REGS_SOUTH_SHARED) #define I2C_CLOCK_DIRECTION_MASK (1 << 0) #define I2C_CLOCK_DIRECTION_OUT (1 << 1) @@ -869,6 +872,15 @@ struct intel_free_graphics_memory { #define I2C_DATA_VALUE_IN (1 << 12) #define I2C_RESERVED ((1 << 13) | (1 << 5)) +// gpu block clock gating disable bits +#define INTEL_DSPCLK_GATE_D (0x2020 | REGS_SOUTH_SHARED) +#define PCH_GMBUSUNIT_CLK_GATE_DIS (1UL << 31) +#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) + // TODO: on IronLake this is in the north shared block at 0x41000 #define INTEL_VGA_DISPLAY_CONTROL (0x1400 | REGS_NORTH_PLANE_CONTROL) #define VGA_DISPLAY_DISABLED (1UL << 31) diff --git a/src/add-ons/accelerants/intel_extreme/Pipes.cpp b/src/add-ons/accelerants/intel_extreme/Pipes.cpp index 3ac2797688..6d70e832f5 100644 --- a/src/add-ons/accelerants/intel_extreme/Pipes.cpp +++ b/src/add-ons/accelerants/intel_extreme/Pipes.cpp @@ -76,7 +76,8 @@ Pipe::Pipe(pipe_index pipeIndex) // IvyBridge: Analog + Digital Ports behind FDI (on northbridge) // Haswell: Only VGA behind FDI (on northbridge) // SkyLake: FDI gone. No more northbridge video. - if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) { + 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"); diff --git a/src/add-ons/accelerants/intel_extreme/Ports.cpp b/src/add-ons/accelerants/intel_extreme/Ports.cpp index 2bef81a91e..416b819fdb 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.cpp +++ b/src/add-ons/accelerants/intel_extreme/Ports.cpp @@ -291,18 +291,22 @@ Port::_SetI2CSignals(void* cookie, int clock, int data) value = read32(ioRegister) & I2C_RESERVED; } + // if we send clk or data, we always send low logic level; + // if we want to send high level, we actually receive and let the + // external pullup resistors create the high level on the bus. + value |= I2C_DATA_VALUE_MASK; //sets data = 0, always latch + value |= I2C_CLOCK_VALUE_MASK; //sets clock = 0, always latch + if (data != 0) value |= I2C_DATA_DIRECTION_MASK; else { - value |= I2C_DATA_DIRECTION_MASK | I2C_DATA_DIRECTION_OUT - | I2C_DATA_VALUE_MASK; + value |= I2C_DATA_DIRECTION_MASK | I2C_DATA_DIRECTION_OUT; } if (clock != 0) value |= I2C_CLOCK_DIRECTION_MASK; else { - value |= I2C_CLOCK_DIRECTION_MASK | I2C_CLOCK_DIRECTION_OUT - | I2C_CLOCK_VALUE_MASK; + value |= I2C_CLOCK_DIRECTION_MASK | I2C_CLOCK_DIRECTION_OUT; } write32(ioRegister, value); @@ -1142,10 +1146,12 @@ DisplayPort::SetDisplayMode(display_mode* target, uint32 colorMode) PanelFitter* fitter = fPipe->PFT(); if (fitter != NULL) fitter->Enable(*target); - FDILink* link = fPipe->FDI(); - if (link != NULL) - link->Train(target); - + // skip FDI if it doesn't exist + if (gInfo->shared_info->device_type.Generation() <= 8) { + FDILink* link = fPipe->FDI(); + if (link != NULL) + link->Train(target); + } pll_divisors divisors; compute_pll_divisors(target, &divisors, false); @@ -1192,6 +1198,7 @@ EmbeddedDisplayPort::IsConnected() TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(), portRegister); + // fixme: Skylake and up use eDP for a seperate active VGA converter chip sometimes. if (!gInfo->shared_info->device_type.IsMobile()) { TRACE("%s: skipping eDP on non-mobile GPU\n", __func__); return false; @@ -1249,7 +1256,17 @@ DigitalDisplayInterface::_PortRegister() addr_t DigitalDisplayInterface::_DDCRegister() { - // TODO: No idea, does DDI have DDC? + switch (PortIndex()) { + case INTEL_PORT_B: + return INTEL_I2C_IO_E; + case INTEL_PORT_C: + return INTEL_I2C_IO_D; + case INTEL_PORT_D: + return INTEL_I2C_IO_F; + default: + return 0; + } + return 0; } @@ -1257,6 +1274,10 @@ DigitalDisplayInterface::_DDCRegister() status_t DigitalDisplayInterface::Power(bool enabled) { + if (fPipe == NULL) { + ERROR("%s: Setting power without assigned pipe!\n", __func__); + return B_ERROR; + } TRACE("%s: %s DDI enabled: %s\n", __func__, PortName(), enabled ? "true" : "false"); @@ -1283,11 +1304,6 @@ DigitalDisplayInterface::IsConnected() if (portRegister == 0) return false; - if ((read32(portRegister) & DDI_INIT_DISPLAY_DETECTED) == 0) { - TRACE("%s: %s link not detected\n", __func__, PortName()); - return false; - } - // Probe a little port info. if ((read32(DDI_BUF_CTL_A) & DDI_A_4_LANES) != 0) { switch (PortIndex()) { @@ -1318,7 +1334,6 @@ DigitalDisplayInterface::IsConnected() TRACE("%s: %s Maximum Lanes: %" B_PRId8 "\n", __func__, PortName(), fMaxLanes); - //DDI and also its EDID do not work yet, we fail on purpose as a workaround for now return HasEDID(); } @@ -1339,11 +1354,14 @@ DigitalDisplayInterface::SetDisplayMode(display_mode* target, uint32 colorMode) PanelFitter* fitter = fPipe->PFT(); if (fitter != NULL) fitter->Enable(target->timing); - // Skip FDI if we have a CPU connected display - if (PortIndex() != INTEL_PORT_A) { - FDILink* link = fPipe->FDI(); - if (link != NULL) - link->Train(&target->timing); + // skip FDI if it doesn't exist + if (gInfo->shared_info->device_type.Generation() <= 8) { + // Skip FDI if we have a CPU connected display + if (PortIndex() != INTEL_PORT_A) { + FDILink* link = fPipe->FDI(); + if (link != NULL) + link->Train(&target->timing); + } } pll_divisors divisors; diff --git a/src/add-ons/accelerants/intel_extreme/accelerant.cpp b/src/add-ons/accelerants/intel_extreme/accelerant.cpp index 8270e9520b..b1e889ffa5 100644 --- a/src/add-ons/accelerants/intel_extreme/accelerant.cpp +++ b/src/add-ons/accelerants/intel_extreme/accelerant.cpp @@ -255,6 +255,21 @@ probe_ports() bool foundDDI = false; gInfo->port_count = 0; +#if 0 + // make sure I2C hardware controller is off (we use bit-banging) + if (gInfo->shared_info->device_type.Generation() >= 5) { + write32(INTEL_DSPCLK_GATE_D, + read32(INTEL_DSPCLK_GATE_D) | PCH_GMBUSUNIT_CLK_GATE_DIS); + read32(INTEL_DSPCLK_GATE_D); + + write32(INTEL_GEN9_CLKGATE_DIS_4, + read32(INTEL_GEN9_CLKGATE_DIS_4) | BXT_GMBUSUNIT_CLK_GATE_DIS); + read32(INTEL_GEN9_CLKGATE_DIS_4); + + write32(INTEL_GMBUS0, 0); //reset, idle + write32(INTEL_GMBUS4, 0); //block interrupts + } +#endif // Display Port if (!gInfo->shared_info->device_type.HasDDI()) { @@ -272,9 +287,9 @@ probe_ports() } } - // Digital Display Interface + // Digital Display Interface (for DP, HDMI and DVI) if (gInfo->shared_info->device_type.HasDDI()) { - for (int i = INTEL_PORT_A; i <= INTEL_PORT_E; i++) { + for (int i = INTEL_PORT_B; i <= INTEL_PORT_D; i++) { TRACE("Probing DDI %d\n", i); Port* ddiPort @@ -292,6 +307,7 @@ probe_ports() } // Ensure DP_A isn't already taken (or DDI) + // Please note that Skylake and up use eDP for a seperate active VGA converter chip. TRACE("Probing eDP\n"); if (!has_connected_port((port_index)INTEL_PORT_A, INTEL_PORT_TYPE_ANY)) { // also always try eDP, it'll also just fail if not applicable @@ -304,64 +320,72 @@ probe_ports() delete eDPPort; } - for (int i = INTEL_PORT_B; i <= INTEL_PORT_D; i++) { - TRACE("Probing HDMI %d\n", i); - if (has_connected_port((port_index)i, INTEL_PORT_TYPE_ANY)) { - // Ensure port not already claimed by something like DDI - TRACE("Port already claimed\n"); - continue; - } + if (!gInfo->shared_info->device_type.HasDDI()) { + for (int i = INTEL_PORT_B; i <= INTEL_PORT_D; i++) { + TRACE("Probing HDMI %d\n", i); + if (has_connected_port((port_index)i, INTEL_PORT_TYPE_ANY)) { + // Ensure port not already claimed by something like DDI + TRACE("Port already claimed\n"); + continue; + } - Port* hdmiPort = new(std::nothrow) HDMIPort((port_index)i); - if (hdmiPort == NULL) - return B_NO_MEMORY; - - if (hdmiPort->IsConnected()) - gInfo->ports[gInfo->port_count++] = hdmiPort; - else - delete hdmiPort; - } - - // always try the LVDS port, it'll simply fail if not applicable - TRACE("Probing LVDS\n"); - Port* lvdsPort = new(std::nothrow) LVDSPort(); - if (lvdsPort == NULL) - return B_NO_MEMORY; - if (lvdsPort->IsConnected()) { - foundLVDS = true; - gInfo->ports[gInfo->port_count++] = lvdsPort; - gInfo->head_mode |= HEAD_MODE_LVDS_PANEL; - gInfo->head_mode |= HEAD_MODE_B_DIGITAL; - } else - delete lvdsPort; - - if (!has_connected_port(INTEL_PORT_ANY, INTEL_PORT_TYPE_ANY)) { - TRACE("Probing DVI\n"); - // there's neither DisplayPort nor HDMI so far, assume DVI B - for (port_index index = INTEL_PORT_B; index <= INTEL_PORT_C; - index = (port_index)(index + 1)) { - Port* dviPort = new(std::nothrow) DigitalPort(index, "DVI"); - if (dviPort == NULL) + Port* hdmiPort = new(std::nothrow) HDMIPort((port_index)i); + if (hdmiPort == NULL) return B_NO_MEMORY; - if (dviPort->IsConnected()) { - gInfo->ports[gInfo->port_count++] = dviPort; - gInfo->head_mode |= HEAD_MODE_B_DIGITAL; - } else - delete dviPort; + if (hdmiPort->IsConnected()) + gInfo->ports[gInfo->port_count++] = hdmiPort; + else + delete hdmiPort; } } - // then finally always try the analog port - TRACE("Probing Analog\n"); - Port* analogPort = new(std::nothrow) AnalogPort(); - if (analogPort == NULL) - return B_NO_MEMORY; - if (analogPort->IsConnected()) { - gInfo->ports[gInfo->port_count++] = analogPort; - gInfo->head_mode |= HEAD_MODE_A_ANALOG; - } else - delete analogPort; + // always try the LVDS port when chipset supports it, it'll simply fail if not applicable + if (!gInfo->shared_info->device_type.HasDDI()) { + TRACE("Probing LVDS\n"); + Port* lvdsPort = new(std::nothrow) LVDSPort(); + if (lvdsPort == NULL) + return B_NO_MEMORY; + if (lvdsPort->IsConnected()) { + foundLVDS = true; + gInfo->ports[gInfo->port_count++] = lvdsPort; + gInfo->head_mode |= HEAD_MODE_LVDS_PANEL; + gInfo->head_mode |= HEAD_MODE_B_DIGITAL; + } else + delete lvdsPort; + } + + if (!gInfo->shared_info->device_type.HasDDI()) { + if (!has_connected_port(INTEL_PORT_ANY, INTEL_PORT_TYPE_ANY)) { + TRACE("Probing DVI\n"); + // there's neither DisplayPort nor HDMI so far, assume DVI B + for (port_index index = INTEL_PORT_B; index <= INTEL_PORT_C; + index = (port_index)(index + 1)) { + Port* dviPort = new(std::nothrow) DigitalPort(index, "DVI"); + if (dviPort == NULL) + return B_NO_MEMORY; + + if (dviPort->IsConnected()) { + gInfo->ports[gInfo->port_count++] = dviPort; + gInfo->head_mode |= HEAD_MODE_B_DIGITAL; + } else + delete dviPort; + } + } + } + + // then finally always try the analog port when chipsets supports it + if (gInfo->shared_info->device_type.Generation() <= 8) { + TRACE("Probing Analog\n"); + Port* analogPort = new(std::nothrow) AnalogPort(); + if (analogPort == NULL) + return B_NO_MEMORY; + if (analogPort->IsConnected()) { + gInfo->ports[gInfo->port_count++] = analogPort; + gInfo->head_mode |= HEAD_MODE_A_ANALOG; + } else + delete analogPort; + } if (gInfo->port_count == 0) return B_ERROR;