intel_extreme: Improve PCH detection
* Detect PCH model based on ISA bridge and save into shared info for later use. * On CougarPoint PCH systems, assign pipes via special CPT registers * Drop HasPlatformControlHub as PCH should be based on more than just generation.
This commit is contained in:
parent
8199f204da
commit
92e254d047
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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__);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue