diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index 7d0ee2dfad..0a5e951f7c 100644 --- a/headers/private/graphics/intel_extreme/intel_extreme.h +++ b/headers/private/graphics/intel_extreme/intel_extreme.h @@ -83,6 +83,17 @@ #define INTEL_MODEL_SKYM (INTEL_GROUP_SKY | INTEL_TYPE_MOBILE) #define INTEL_MODEL_SKYS (INTEL_GROUP_SKY | INTEL_TYPE_SERVER) +#define INTEL_PCH_DEVICE_ID_MASK 0xff00 +#define INTEL_PCH_IBX_DEVICE_ID 0x3b00 +#define INTEL_PCH_CPT_DEVICE_ID 0x1c00 +#define INTEL_PCH_PPT_DEVICE_ID 0x1e00 +#define INTEL_PCH_LPT_DEVICE_ID 0x8c00 +#define INTEL_PCH_LPT_LP_DEVICE_ID 0x9c00 +#define INTEL_PCH_SPT_DEVICE_ID 0xA100 +#define INTEL_PCH_SPT_LP_DEVICE_ID 0x9D00 +#define INTEL_PCH_P2X_DEVICE_ID 0x7100 +#define INTEL_PCH_P3X_DEVICE_ID 0x7000 + // ValleyView MMIO offset #define VLV_DISPLAY_BASE 0x180000 @@ -163,11 +174,6 @@ struct DeviceType { || InFamily(INTEL_FAMILY_SOC0); } - bool HasPlatformControlHub() const - { - return InFamily(INTEL_FAMILY_SER5); - } - bool HasDDI() const { // Intel Digital Display Interface @@ -201,6 +207,15 @@ struct DeviceType { } }; +enum pch_info { + INTEL_PCH_NONE = 0, // No PCH present + INTEL_PCH_IBX, // Ibexpeak + INTEL_PCH_CPT, // Cougarpoint + INTEL_PCH_LPT, // Lynxpoint + INTEL_PCH_SPT, // Sunrisepoint + INTEL_PCH_NOP +}; + // info about PLL on graphics card struct pll_info { uint32 reference_frequency; @@ -273,6 +288,8 @@ struct intel_shared_info { char device_identifier[32]; struct pll_info pll_info; + enum pch_info pch_info; + edid1_info vesa_edid_info; bool has_vesa_edid_info; }; @@ -473,7 +490,6 @@ struct intel_free_graphics_memory { #define LVDS_18BIT_DITHER (1UL << 25) #define LVDS_PORT_EN (1UL << 31) - // PLL flags #define DISPLAY_PLL_ENABLED (1UL << 31) #define DISPLAY_PLL_2X_CLOCK (1UL << 30) @@ -520,6 +536,12 @@ struct intel_free_graphics_memory { #define INTEL_DISPLAY_A_IMAGE_SIZE (0x001c | REGS_NORTH_PIPE_AND_PORT) #define INTEL_DISPLAY_B_IMAGE_SIZE (0x101c | REGS_NORTH_PIPE_AND_PORT) +// Cougar Point transcoder pipe selection +#define PORT_TRANS_A_SEL_CPT 0 +#define PORT_TRANS_B_SEL_CPT (1<<29) +#define PORT_TRANS_C_SEL_CPT (2<<29) +#define PORT_TRANS_SEL_MASK (3<<29) + // on PCH we also have to set the transcoder #define INTEL_TRANSCODER_A_HTOTAL (0x0000 | REGS_SOUTH_TRANSCODER_PORT) #define INTEL_TRANSCODER_A_HBLANK (0x0004 | REGS_SOUTH_TRANSCODER_PORT) diff --git a/src/add-ons/accelerants/intel_extreme/Pipes.cpp b/src/add-ons/accelerants/intel_extreme/Pipes.cpp index 2848d0a449..0014837f55 100644 --- a/src/add-ons/accelerants/intel_extreme/Pipes.cpp +++ b/src/add-ons/accelerants/intel_extreme/Pipes.cpp @@ -67,7 +67,7 @@ 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->device_type.HasPlatformControlHub()) { + if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) { TRACE("%s: Pipe %s routed through FDI\n", __func__, (pipeIndex == INTEL_PIPE_A) ? "A" : "B"); @@ -136,6 +136,10 @@ Pipe::Configure(display_mode* mode) void Pipe::_ConfigureTranscoder(display_mode* target) { + CALLED(); + + TRACE("%s: fPipeOffset: 0x%" B_PRIx32"\n", __func__, fPipeOffset); + // update timing (fPipeOffset bumps the DISPLAY_A to B when needed) write32(INTEL_TRANSCODER_A_HTOTAL + fPipeOffset, ((uint32)(target->timing.h_total - 1) << 16) @@ -172,6 +176,8 @@ Pipe::ConfigureTimings(display_mode* target) { CALLED(); + TRACE("%s: fPipeOffset: 0x%" B_PRIx32"\n", __func__, fPipeOffset); + if (target == NULL) { ERROR("%s: Invalid display mode!\n", __func__); return; @@ -199,6 +205,7 @@ Pipe::ConfigureTimings(display_mode* target) | ((uint32)target->timing.v_sync_start - 1)); // XXX: Is it ok to do these on non-digital? + write32(INTEL_DISPLAY_A_POS + fPipeOffset, 0); write32(INTEL_DISPLAY_A_IMAGE_SIZE + fPipeOffset, ((uint32)(target->virtual_width - 1) << 16) diff --git a/src/add-ons/accelerants/intel_extreme/Ports.cpp b/src/add-ons/accelerants/intel_extreme/Ports.cpp index 14e707d020..eeae37fef8 100644 --- a/src/add-ons/accelerants/intel_extreme/Ports.cpp +++ b/src/add-ons/accelerants/intel_extreme/Ports.cpp @@ -130,10 +130,18 @@ Port::SetPipe(Pipe* pipe) uint32 portState = read32(portRegister); - if (pipe->Index() == INTEL_PIPE_A) - write32(portRegister, portState & ~DISPLAY_MONITOR_PIPE_B); - else - write32(portRegister, portState | DISPLAY_MONITOR_PIPE_B); + if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { + portState &= PORT_TRANS_SEL_MASK; + if (pipe->Index() == INTEL_PIPE_A) + write32(portRegister, portState | PORT_TRANS_A_SEL_CPT); + else + write32(portRegister, portState | PORT_TRANS_B_SEL_CPT); + } else { + if (pipe->Index() == INTEL_PIPE_A) + write32(portRegister, portState & ~DISPLAY_MONITOR_PIPE_B); + else + write32(portRegister, portState | DISPLAY_MONITOR_PIPE_B); + } fPipe = pipe; @@ -348,7 +356,7 @@ LVDSPort::LVDSPort() { // Always unlock LVDS port as soon as we start messing with it. uint32 panelControl = INTEL_PANEL_CONTROL; - if (gInfo->shared_info->device_type.HasPlatformControlHub()) + if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) panelControl = PCH_PANEL_CONTROL; write32(panelControl, read32(panelControl) | PANEL_REGISTER_UNLOCK); } @@ -360,7 +368,7 @@ LVDSPort::IsConnected() TRACE("%s: %s PortRegister: 0x%" B_PRIxADDR "\n", __func__, PortName(), _PortRegister()); - if (gInfo->shared_info->device_type.HasPlatformControlHub()) { + if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) { uint32 registerValue = read32(_PortRegister()); // there's a detection bit we can use if ((registerValue & PCH_LVDS_DETECTED) == 0) { @@ -438,7 +446,7 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode) addr_t panelControl = INTEL_PANEL_CONTROL; addr_t panelStatus = INTEL_PANEL_STATUS; - if (gInfo->shared_info->device_type.HasPlatformControlHub()) { + if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) { panelControl = PCH_PANEL_CONTROL; panelStatus = PCH_PANEL_STATUS; } @@ -504,6 +512,15 @@ LVDSPort::SetDisplayMode(display_mode* target, uint32 colorMode) lvds |= LVDS_18BIT_DITHER; } + // LVDS on PCH needs set before display enable + if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { + lvds &= PORT_TRANS_SEL_MASK; + if (fPipe->Index() == INTEL_PIPE_A) + lvds |= PORT_TRANS_A_SEL_CPT; + else + lvds |= PORT_TRANS_B_SEL_CPT; + } + // Set the B0-B3 data pairs corresponding to whether we're going to // set the DPLLs for dual-channel mode or not. if (divisors.p2 == 5 || divisors.p2 == 7) { @@ -763,8 +780,8 @@ HDMIPort::IsConnected() if (portRegister == 0) return false; - if (!gInfo->shared_info->device_type.HasPlatformControlHub() - && PortIndex() == INTEL_PORT_C) { + bool hasPCH = (gInfo->shared_info->pch_info != INTEL_PCH_NONE); + if (!hasPCH && PortIndex() == INTEL_PORT_C) { // there's no detection bit on this port } else if ((read32(portRegister) & DISPLAY_MONITOR_PORT_DETECTED) == 0) return false; @@ -777,7 +794,7 @@ addr_t HDMIPort::_PortRegister() { // on PCH there's an additional port sandwiched in - bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub(); + bool hasPCH = (gInfo->shared_info->pch_info != INTEL_PCH_NONE); bool fourthGen = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV); switch (PortIndex()) { diff --git a/src/add-ons/accelerants/intel_extreme/dpms.cpp b/src/add-ons/accelerants/intel_extreme/dpms.cpp index babdca6f84..b21974fc38 100644 --- a/src/add-ons/accelerants/intel_extreme/dpms.cpp +++ b/src/add-ons/accelerants/intel_extreme/dpms.cpp @@ -46,7 +46,7 @@ enable_all_pipes(bool enable) static void enable_lvds_panel(bool enable) { - bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub(); + bool hasPCH = (gInfo->shared_info->pch_info != INTEL_PCH_NONE); int controlRegister = hasPCH ? PCH_PANEL_CONTROL : INTEL_PANEL_CONTROL; int statusRegister = hasPCH ? PCH_PANEL_STATUS : INTEL_PANEL_STATUS; diff --git a/src/add-ons/accelerants/intel_extreme/pll.cpp b/src/add-ons/accelerants/intel_extreme/pll.cpp index 1c4cfb3f39..fa6b9cb4e6 100644 --- a/src/add-ons/accelerants/intel_extreme/pll.cpp +++ b/src/add-ons/accelerants/intel_extreme/pll.cpp @@ -446,7 +446,7 @@ void compute_pll_divisors(display_mode* current, pll_divisors* divisors, bool isLVDS) { if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x) - || gInfo->shared_info->device_type.HasPlatformControlHub()) { + || (gInfo->shared_info->pch_info != INTEL_PCH_NONE)) { compute_dpll_g4x(current, divisors, isLVDS); } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) { ERROR("%s: TODO: CherryView\n", __func__); diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp index 8e0c13adcc..5a84537153 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/driver.cpp @@ -170,6 +170,47 @@ get_next_intel_extreme(int32* _cookie, pci_info &info, uint32 &type) } +static enum pch_info +detect_intel_pch() +{ + pci_info info; + + // find devices + for (int32 i = 0; gPCI->get_nth_pci_info(i, &info) == B_OK; i++) { + // check vendor + if (info.vendor_id != VENDOR_ID_INTEL + || info.class_base != PCI_bridge + || info.class_sub != PCI_isa) { + continue; + } + + // check device + unsigned short id = info.device_id & INTEL_PCH_DEVICE_ID_MASK; + switch(id) { + case INTEL_PCH_IBX_DEVICE_ID: + ERROR("%s: Found Ibex Peak PCH\n", __func__); + return INTEL_PCH_IBX; + case INTEL_PCH_CPT_DEVICE_ID: + ERROR("%s: Found CougarPoint PCH\n", __func__); + return INTEL_PCH_CPT; + case INTEL_PCH_PPT_DEVICE_ID: + ERROR("%s: Found PantherPoint PCH\n", __func__); + return INTEL_PCH_CPT; + case INTEL_PCH_LPT_DEVICE_ID: + ERROR("%s: Found LynxPoint PCH\n", __func__); + return INTEL_PCH_LPT; + case INTEL_PCH_SPT_DEVICE_ID: + case INTEL_PCH_SPT_LP_DEVICE_ID: + ERROR("%s: Found SunrisePoint PCH\n", __func__); + return INTEL_PCH_SPT; + } + } + + ERROR("%s: No PCH detected.\n", __func__); + return INTEL_PCH_NONE; +} + + extern "C" const char** publish_devices(void) { @@ -226,6 +267,8 @@ init_driver(void) gPCIx86Module = NULL; } + // find the PCH device (if any) + enum pch_info pchInfo = detect_intel_pch(); // find devices @@ -269,6 +312,7 @@ init_driver(void) gDeviceInfo[found]->registers = info->u.h0.base_registers[0]; gDeviceInfo[found]->device_identifier = kSupportedDevices[type].name; gDeviceInfo[found]->device_type = kSupportedDevices[type].type; + gDeviceInfo[found]->pch_info = pchInfo; dprintf(DEVICE_NAME ": (%ld) %s, revision = 0x%x\n", found, kSupportedDevices[type].name, info->revision); diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp index f9af40e1f3..9f19a9193e 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp @@ -93,7 +93,7 @@ intel_interrupt_handler(void* data) while (identity != 0) { // TODO: verify that these aren't actually the same - bool hasPCH = info.device_type.HasPlatformControlHub(); + bool hasPCH = (info.pch_info != INTEL_PCH_NONE); uint16 mask; // Intel changed the PCH register mapping between Sandy Bridge and the @@ -215,7 +215,7 @@ init_interrupt_handler(intel_info &info) write16(info, find_reg(info, INTEL_INTERRUPT_IDENTITY), ~0); // enable interrupts - we only want VBLANK interrupts - bool hasPCH = info.device_type.HasPlatformControlHub(); + bool hasPCH = (info.pch_info != INTEL_PCH_NONE); uint16 enable = hasPCH ? (PCH_INTERRUPT_VBLANK_PIPEA | PCH_INTERRUPT_VBLANK_PIPEB) : (INTERRUPT_VBLANK_PIPEA | INTERRUPT_VBLANK_PIPEB); @@ -316,15 +316,16 @@ intel_extreme_init(intel_info &info) return info.registers_area; } + bool hasPCH = (info.pch_info != INTEL_PCH_NONE); + ERROR("Init Intel generation %" B_PRId32 " GPU %s PCH split.\n", - info.device_type.Generation(), - info.device_type.HasPlatformControlHub() ? "with" : "without"); + info.device_type.Generation(), hasPCH ? "with" : "without"); uint32* blocks = info.shared_info->register_blocks; blocks[REGISTER_BLOCK(REGS_FLAT)] = 0; // setup the register blocks for the different architectures - if (info.device_type.HasPlatformControlHub()) { + if (hasPCH) { // PCH based platforms (IronLake through ultra-low-power Broadwells) blocks[REGISTER_BLOCK(REGS_NORTH_SHARED)] = PCH_NORTH_SHARED_REGISTER_BASE; @@ -428,6 +429,8 @@ intel_extreme_init(intel_info &info) info.shared_info->pll_info.divisor_register = INTEL_DISPLAY_A_PLL_DIVISOR_0; + info.shared_info->pch_info = info.pch_info; + info.shared_info->device_type = info.device_type; #ifdef __HAIKU__ strlcpy(info.shared_info->device_identifier, info.device_identifier, @@ -474,7 +477,7 @@ intel_extreme_init(intel_info &info) init_interrupt_handler(info); - if (info.device_type.HasPlatformControlHub()) { + if (hasPCH) { if (info.device_type.Generation() == 5) { info.shared_info->fdi_link_frequency = (read32(info, FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2; diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme_private.h b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme_private.h index 0632c57bc9..3c4a0b48d0 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme_private.h +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme_private.h @@ -40,6 +40,8 @@ struct intel_info { const char* device_identifier; DeviceType device_type; + + enum pch_info pch_info; }; @@ -51,7 +53,7 @@ find_reg(const intel_info& info, uint32 target) return target; } - if (!info.device_type.HasPlatformControlHub()) + if (info.pch_info == INTEL_PCH_NONE) return target; #define RETURN_REG(x) case INTEL_##x: return PCH_##x;