Merge branch 'intel-extreme'

Rework of the intel-extreme driver. Don't expect anything special yet.
This commit is contained in:
Alexander von Gluck IV
2016-04-09 14:12:52 -05:00
27 changed files with 3857 additions and 1324 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Copyright 2012-2016 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@@ -1,9 +1,10 @@
/*
* Copyright 2006-2014, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2016, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
* Alexander von Gluck, [email protected]
*/
#ifndef INTEL_EXTREME_H
#define INTEL_EXTREME_H
@@ -20,50 +21,61 @@
#define VENDOR_ID_INTEL 0x8086
#define INTEL_TYPE_FAMILY_MASK 0x000f0000
#define INTEL_TYPE_GROUP_MASK 0x000ffff0
#define INTEL_TYPE_MODEL_MASK 0x000fffff
#define INTEL_FAMILY_MASK 0x00ff0000
#define INTEL_GROUP_MASK 0x00fffff0
#define INTEL_MODEL_MASK 0x00ffffff
#define INTEL_TYPE_MASK 0x0000000f
// families
#define INTEL_TYPE_7xx 0x00010000
#define INTEL_TYPE_8xx 0x00020000
#define INTEL_TYPE_9xx 0x00040000
#define INTEL_FAMILY_7xx 0x00010000 // First Gen
#define INTEL_FAMILY_8xx 0x00020000 // Second Gen
#define INTEL_FAMILY_9xx 0x00040000 // Third Gen +
#define INTEL_FAMILY_SER5 0x00080000 // Intel5 Series
#define INTEL_FAMILY_POVR 0x00100000 // PowerVR (uugh)
#define INTEL_FAMILY_SOC0 0x00200000 // Atom SOC
// groups
#define INTEL_TYPE_83x (INTEL_TYPE_8xx | 0x0010)
#define INTEL_TYPE_85x (INTEL_TYPE_8xx | 0x0020)
#define INTEL_TYPE_91x (INTEL_TYPE_9xx | 0x0040)
#define INTEL_TYPE_94x (INTEL_TYPE_9xx | 0x0080)
#define INTEL_TYPE_96x (INTEL_TYPE_9xx | 0x0100)
#define INTEL_TYPE_Gxx (INTEL_TYPE_9xx | 0x0200)
#define INTEL_TYPE_G4x (INTEL_TYPE_9xx | 0x0400)
#define INTEL_TYPE_IGD (INTEL_TYPE_9xx | 0x0800)
#define INTEL_TYPE_ILK (INTEL_TYPE_9xx | 0x1000)
#define INTEL_TYPE_SNB (INTEL_TYPE_9xx | 0x2000)
#define INTEL_TYPE_IVB (INTEL_TYPE_9xx | 0x4000)
#define INTEL_TYPE_VLV (INTEL_TYPE_9xx | 0x8000)
#define INTEL_GROUP_83x (INTEL_FAMILY_8xx | 0x0010)
#define INTEL_GROUP_85x (INTEL_FAMILY_8xx | 0x0020)
#define INTEL_GROUP_91x (INTEL_FAMILY_9xx | 0x0010)
#define INTEL_GROUP_94x (INTEL_FAMILY_9xx | 0x0020)
#define INTEL_GROUP_96x (INTEL_FAMILY_9xx | 0x0040)
#define INTEL_GROUP_Gxx (INTEL_FAMILY_9xx | 0x0080)
#define INTEL_GROUP_G4x (INTEL_FAMILY_9xx | 0x0100)
#define INTEL_GROUP_PIN (INTEL_FAMILY_9xx | 0x0200) // PineView
#define INTEL_GROUP_ILK (INTEL_FAMILY_SER5 | 0x0010) // IronLake
#define INTEL_GROUP_SNB (INTEL_FAMILY_SER5 | 0x0020) // SandyBridge
#define INTEL_GROUP_IVB (INTEL_FAMILY_SER5 | 0x0040) // IvyBridge
#define INTEL_GROUP_HAS (INTEL_FAMILY_SER5 | 0x0080) // Haswell
#define INTEL_GROUP_SLT (INTEL_FAMILY_POVR | 0x0010) // Saltwell
#define INTEL_GROUP_FSM (INTEL_FAMILY_POVR | 0x0020) // Fu.Silvermont
#define INTEL_GROUP_VLV (INTEL_FAMILY_SOC0 | 0x0010) // ValleyView
#define INTEL_GROUP_CHV (INTEL_FAMILY_SOC0 | 0x0020) // CherryView
#define INTEL_GROUP_BXT (INTEL_FAMILY_SOC0 | 0x0040) // Broxton
// models
#define INTEL_TYPE_SERVER 0x0004
#define INTEL_TYPE_MOBILE 0x0008
#define INTEL_TYPE_915 (INTEL_TYPE_91x)
#define INTEL_TYPE_915M (INTEL_TYPE_91x | INTEL_TYPE_MOBILE)
#define INTEL_TYPE_945 (INTEL_TYPE_94x)
#define INTEL_TYPE_945M (INTEL_TYPE_94x | INTEL_TYPE_MOBILE)
#define INTEL_TYPE_965 (INTEL_TYPE_96x)
#define INTEL_TYPE_965M (INTEL_TYPE_96x | INTEL_TYPE_MOBILE)
#define INTEL_TYPE_G33 (INTEL_TYPE_Gxx)
#define INTEL_TYPE_G45 (INTEL_TYPE_G4x)
#define INTEL_TYPE_GM45 (INTEL_TYPE_G4x | INTEL_TYPE_MOBILE)
#define INTEL_TYPE_IGDG (INTEL_TYPE_IGD)
#define INTEL_TYPE_IGDGM (INTEL_TYPE_IGD | INTEL_TYPE_MOBILE)
#define INTEL_TYPE_ILKG (INTEL_TYPE_ILK)
#define INTEL_TYPE_ILKGM (INTEL_TYPE_ILK | INTEL_TYPE_MOBILE)
#define INTEL_TYPE_SNBG (INTEL_TYPE_SNB)
#define INTEL_TYPE_SNBGM (INTEL_TYPE_SNB | INTEL_TYPE_MOBILE)
#define INTEL_TYPE_SNBGS (INTEL_TYPE_SNB | INTEL_TYPE_SERVER)
#define INTEL_TYPE_IVBG (INTEL_TYPE_IVB)
#define INTEL_TYPE_IVBGM (INTEL_TYPE_IVB | INTEL_TYPE_MOBILE)
#define INTEL_TYPE_IVBGS (INTEL_TYPE_IVB | INTEL_TYPE_SERVER)
#define INTEL_TYPE_VLVG (INTEL_TYPE_VLV)
#define INTEL_TYPE_VLVGM (INTEL_TYPE_VLV | INTEL_TYPE_MOBILE)
#define INTEL_TYPE_SERVER 0x0004
#define INTEL_TYPE_MOBILE 0x0008
#define INTEL_MODEL_915 (INTEL_GROUP_91x)
#define INTEL_MODEL_915M (INTEL_GROUP_91x | INTEL_TYPE_MOBILE)
#define INTEL_MODEL_945 (INTEL_GROUP_94x)
#define INTEL_MODEL_945M (INTEL_GROUP_94x | INTEL_TYPE_MOBILE)
#define INTEL_MODEL_965 (INTEL_GROUP_96x)
#define INTEL_MODEL_965M (INTEL_GROUP_96x | INTEL_TYPE_MOBILE)
#define INTEL_MODEL_G33 (INTEL_GROUP_Gxx)
#define INTEL_MODEL_G45 (INTEL_GROUP_G4x)
#define INTEL_MODEL_GM45 (INTEL_GROUP_G4x | INTEL_TYPE_MOBILE)
#define INTEL_MODEL_PINE (INTEL_GROUP_PIN)
#define INTEL_MODEL_PINEM (INTEL_GROUP_PIN | INTEL_TYPE_MOBILE)
#define INTEL_MODEL_ILKG (INTEL_GROUP_ILK)
#define INTEL_MODEL_ILKGM (INTEL_GROUP_ILK | INTEL_TYPE_MOBILE)
#define INTEL_MODEL_SNBG (INTEL_GROUP_SNB)
#define INTEL_MODEL_SNBGM (INTEL_GROUP_SNB | INTEL_TYPE_MOBILE)
#define INTEL_MODEL_SNBGS (INTEL_GROUP_SNB | INTEL_TYPE_SERVER)
#define INTEL_MODEL_IVBG (INTEL_GROUP_IVB)
#define INTEL_MODEL_IVBGM (INTEL_GROUP_IVB | INTEL_TYPE_MOBILE)
#define INTEL_MODEL_IVBGS (INTEL_GROUP_IVB | INTEL_TYPE_SERVER)
#define INTEL_MODEL_HAS (INTEL_GROUP_HAS)
#define INTEL_MODEL_HASM (INTEL_GROUP_HAS | INTEL_TYPE_MOBILE)
#define INTEL_MODEL_VLV (INTEL_GROUP_VLV)
#define INTEL_MODEL_VLVM (INTEL_GROUP_VLV | INTEL_TYPE_MOBILE)
// ValleyView MMIO offset
#define VLV_DISPLAY_BASE 0x180000
@@ -94,10 +106,10 @@
#define ICH_SHARED_REGISTER_BASE 0x00000
#define ICH_PORT_REGISTER_BASE 0x60000
// PCH - Platform Control Hub - Newer hardware moves from a MCH/ICH based setup
// to a PCH based one, that means anything that used to communicate via (G)MCH
// registers needs to use different ones on PCH based platforms (Ironlake and
// up, SandyBridge, etc.).
// PCH - Platform Control Hub - Some hardware moves from a MCH/ICH based
// setup to a PCH based one, that means anything that used to communicate via
// (G)MCH registers needs to use different ones on PCH based platforms
// (Ironlake, SandyBridge, IvyBridge, Some Haswell).
#define PCH_NORTH_SHARED_REGISTER_BASE 0x40000
#define PCH_NORTH_PIPE_AND_PORT_REGISTER_BASE 0x60000
#define PCH_NORTH_PLANE_CONTROL_REGISTER_BASE 0x70000
@@ -121,23 +133,65 @@ struct DeviceType {
bool InFamily(uint32 family) const
{
return (type & INTEL_TYPE_FAMILY_MASK) == family;
return (type & INTEL_FAMILY_MASK) == family;
}
bool InGroup(uint32 group) const
{
return (type & INTEL_TYPE_GROUP_MASK) == group;
return (type & INTEL_GROUP_MASK) == group;
}
bool IsModel(uint32 model) const
{
return (type & INTEL_TYPE_MODEL_MASK) == model;
return (type & INTEL_MODEL_MASK) == model;
}
bool IsMobile() const
{
return (type & INTEL_TYPE_MASK) == INTEL_TYPE_MOBILE;
}
bool SupportsHDMI() const
{
return InGroup(INTEL_GROUP_G4x) || InFamily(INTEL_FAMILY_SER5)
|| InFamily(INTEL_FAMILY_SOC0);
}
bool HasPlatformControlHub() const
{
return InGroup(INTEL_TYPE_ILK) || InGroup(INTEL_TYPE_SNB)
|| InGroup(INTEL_TYPE_IVB) || InGroup(INTEL_TYPE_VLV);
return InFamily(INTEL_FAMILY_SER5);
}
bool HasDDI() const
{
// Intel Digital Display Interface
return InGroup(INTEL_GROUP_HAS) || (Generation() >= 8);
}
int Generation() const
{
if (InFamily(INTEL_FAMILY_7xx))
return 1;
if (InFamily(INTEL_FAMILY_8xx))
return 2;
if (InGroup(INTEL_GROUP_91x) || InGroup(INTEL_GROUP_94x)
|| IsModel(INTEL_MODEL_G33) || InGroup(INTEL_GROUP_PIN))
return 3;
if (InFamily(INTEL_FAMILY_9xx))
return 4;
if (InGroup(INTEL_GROUP_ILK))
return 5;
if (InGroup(INTEL_GROUP_SNB))
return 6;
if (InFamily(INTEL_FAMILY_SER5) || InGroup(INTEL_GROUP_VLV))
return 7;
if (InGroup(INTEL_GROUP_CHV))
return 8;
if (InGroup(INTEL_GROUP_BXT))
return 9;
// Generation 0 means somethins is wrong :-)
return 0;
}
};
@@ -165,12 +219,12 @@ struct intel_shared_info {
area_id mode_list_area; // area containing display mode list
uint32 mode_count;
display_mode current_mode;
display_mode panel_mode; // VBIOS VBT panel mode
uint32 bytes_per_row;
uint32 bits_per_pixel;
uint32 dpms_mode;
area_id registers_area; // area of memory mapped registers
area_id registers_area; // area of memory mapped registers
uint32 register_blocks[REGISTER_BLOCK_COUNT];
uint8* status_page;
@@ -182,6 +236,8 @@ struct intel_shared_info {
addr_t frame_buffer;
uint32 frame_buffer_offset;
uint32 fdi_link_frequency; // In Mhz
bool got_vbt;
bool single_head_locked;
@@ -215,6 +271,12 @@ struct intel_shared_info {
bool has_vesa_edid_info;
};
enum pipe_index {
INTEL_PIPE_ANY,
INTEL_PIPE_A,
INTEL_PIPE_B
};
//----------------- ioctl() interface ----------------
// magic code for ioctls
@@ -254,7 +316,8 @@ struct intel_free_graphics_memory {
// Register definitions, taken from X driver
// PCI bridge memory management
#define INTEL_GRAPHICS_MEMORY_CONTROL 0x52
#define INTEL_GRAPHICS_MEMORY_CONTROL 0x52 // i830+
// GGC - (G)MCH Graphics Control Register
#define MEMORY_CONTROL_ENABLED 0x0004
#define MEMORY_MASK 0x0001
@@ -288,6 +351,7 @@ struct intel_free_graphics_memory {
#define G4X_STOLEN_MEMORY_352MB 0xd0
// SandyBridge (SNB)
#define SNB_GRAPHICS_MEMORY_CONTROL 0x50
#define SNB_STOLEN_MEMORY_MASK 0xf8
@@ -374,7 +438,7 @@ struct intel_free_graphics_memory {
#define PCH_INTERRUPT_VBLANK_PIPEA_SNB (1 << 7)
#define PCH_INTERRUPT_VBLANK_PIPEB_SNB (1 << 15)
// display ports
// graphics port control
#define DISPLAY_MONITOR_PORT_ENABLED (1UL << 31)
#define DISPLAY_MONITOR_PIPE_B (1UL << 30)
#define DISPLAY_MONITOR_VGA_POLARITY (1UL << 15)
@@ -386,23 +450,31 @@ struct intel_free_graphics_memory {
#define DISPLAY_MONITOR_POLARITY_MASK (3UL << 3)
#define DISPLAY_MONITOR_POSITIVE_HSYNC (1UL << 3)
#define DISPLAY_MONITOR_POSITIVE_VSYNC (2UL << 3)
#define DISPLAY_MONITOR_PORT_DETECTED (1UL << 2) // TMDS/DisplayPort only
#define LVDS_POST2_RATE_SLOW 14 // PLL Divisors
#define LVDS_POST2_RATE_FAST 7
#define LVDS_CLKB_POWER_MASK (3 << 4)
#define LVDS_CLKB_POWER_UP (3 << 4)
#define LVDS_PORT_EN (1 << 31)
#define LVDS_A0A2_CLKA_POWER_UP (3 << 8)
#define LVDS_PIPEB_SELECT (1 << 30)
#define LVDS_B0B3PAIRS_POWER_UP (3 << 2)
#define LVDS_PLL_MODE_LVDS (2 << 26)
#define LVDS_18BIT_DITHER (1 << 25)
#define LVDS_B0B3_POWER_MASK (3UL << 2)
#define LVDS_B0B3_POWER_UP (3UL << 2)
#define LVDS_CLKB_POWER_MASK (3UL << 4)
#define LVDS_CLKB_POWER_UP (3UL << 4)
#define LVDS_A3_POWER_MASK (3UL << 6)
#define LVDS_A3_POWER_UP (3UL << 6)
#define LVDS_A0A2_CLKA_POWER_UP (3UL << 8)
#define LVDS_BORDER_ENABLE (1UL << 15)
#define LVDS_HSYNC_POLARITY (1UL << 20)
#define LVDS_VSYNC_POLARITY (1UL << 21)
#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)
#define DISPLAY_PLL_SYNC_LOCK_ENABLED (1UL << 29)
#define DISPLAY_PLL_NO_VGA_CONTROL (1UL << 28)
#define DISPLAY_PLL_MODE_ANALOG (1UL << 26)
#define DISPLAY_PLL_MODE_NORMAL (1UL << 26)
#define DISPLAY_PLL_MODE_LVDS (2UL << 26)
#define DISPLAY_PLL_DIVIDE_HIGH (1UL << 24)
#define DISPLAY_PLL_DIVIDE_4X (1UL << 23)
#define DISPLAY_PLL_POST1_DIVIDE_2 (1UL << 21)
@@ -423,35 +495,122 @@ struct intel_free_graphics_memory {
#define DISPLAY_PLL_PULSE_PHASE_SHIFT 9
// display
#define INTEL_DISPLAY_A_HTOTAL (0x0000 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_A_HBLANK (0x0004 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_A_HSYNC (0x0008 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_A_VTOTAL (0x000c | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_A_VBLANK (0x0010 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_A_VSYNC (0x0014 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_HTOTAL (0x1000 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_HBLANK (0x1004 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_HSYNC (0x1008 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_VTOTAL (0x100c | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_VBLANK (0x1010 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_VSYNC (0x1014 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_OFFSET 0x1000
#define INTEL_DISPLAY_A_HTOTAL (0x0000 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_HBLANK (0x0004 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_HSYNC (0x0008 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_VTOTAL (0x000c | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_VBLANK (0x0010 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_VSYNC (0x0014 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_HTOTAL (0x1000 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_HBLANK (0x1004 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_HSYNC (0x1008 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_VTOTAL (0x100c | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_VBLANK (0x1010 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_VSYNC (0x1014 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_IMAGE_SIZE (0x001c | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_B_IMAGE_SIZE (0x101c | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_A_ANALOG_PORT (0x1100 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_A_DIGITAL_PORT (0x1120 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_B_DIGITAL_PORT (0x1140 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_C_DIGITAL (0x1160 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_LVDS_PORT (0x1180 | REGS_SOUTH_TRANSCODER_PORT)
// 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)
#define INTEL_TRANSCODER_A_HSYNC (0x0008 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_TRANSCODER_A_VTOTAL (0x000c | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_TRANSCODER_A_VBLANK (0x0010 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_TRANSCODER_A_VSYNC (0x0014 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_TRANSCODER_B_HTOTAL (0x1000 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_TRANSCODER_B_HBLANK (0x1004 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_TRANSCODER_B_HSYNC (0x1008 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_TRANSCODER_B_VTOTAL (0x100c | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_TRANSCODER_B_VBLANK (0x1010 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_TRANSCODER_B_VSYNC (0x1014 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_TRANSCODER_A_IMAGE_SIZE (0x001c | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_TRANSCODER_B_IMAGE_SIZE (0x101c | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_ANALOG_PORT (0x1100 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DIGITAL_PORT_A (0x1120 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DIGITAL_PORT_B (0x1140 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DIGITAL_PORT_C (0x1160 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DIGITAL_LVDS_PORT (0x1180 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_HDMI_PORT_B (0x1140 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_HDMI_PORT_C (0x1160 | REGS_SOUTH_TRANSCODER_PORT)
#define PCH_HDMI_PORT_B (0x1140 | REGS_SOUTH_TRANSCODER_PORT)
#define PCH_HDMI_PORT_C (0x1150 | REGS_SOUTH_TRANSCODER_PORT)
#define PCH_HDMI_PORT_D (0x1160 | REGS_SOUTH_TRANSCODER_PORT)
#define GEN4_HDMI_PORT_B (0x1140 | REGS_SOUTH_TRANSCODER_PORT)
#define GEN4_HDMI_PORT_C (0x1160 | REGS_SOUTH_TRANSCODER_PORT)
#define CHV_HDMI_PORT_D (0x116C | REGS_SOUTH_TRANSCODER_PORT)
// DDI Buffer Control (This replaces DP on Haswell+)
#define DDI_BUF_CTL_A (0x4000 | REGS_NORTH_PIPE_AND_PORT)
#define DDI_BUF_CTL_B (0x4100 | REGS_NORTH_PIPE_AND_PORT)
#define DDI_BUF_CTL_ENABLE (1 << 31)
#define DDI_BUF_TRANS_SELECT(n) ((n) << 24)
#define DDI_BUF_EMP_MASK (0xf << 24)
#define DDI_BUF_PORT_REVERSAL (1 << 16)
#define DDI_BUF_IS_IDLE (1 << 7)
#define DDI_A_4_LANES (1 << 4)
#define DDI_PORT_WIDTH(width) (((width) - 1) << 1)
#define DDI_INIT_DISPLAY_DETECTED (1 << 0)
// DP_A always @ 6xxxx, DP_B-DP_D move with PCH
#define INTEL_DISPLAY_PORT_A (0x4000 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DISPLAY_PORT_B (0x4100 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_PORT_C (0x4200 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DISPLAY_PORT_D (0x4300 | REGS_SOUTH_TRANSCODER_PORT)
// Unless you're a damn Valley/CherryView unicorn :-(
#define VLV_DISPLAY_PORT_B (VLV_DISPLAY_BASE + 0x64100)
#define VLV_DISPLAY_PORT_C (VLV_DISPLAY_BASE + 0x64200)
#define CHV_DISPLAY_PORT_D (VLV_DISPLAY_BASE + 0x64300)
// DP AUX channels
#define INTEL_DP_AUX_CTL_A (0x4010 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_DP_AUX_CTL_B (0x4110 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DP_AUX_CTL_C (0x4210 | REGS_SOUTH_TRANSCODER_PORT)
#define INTEL_DP_AUX_CTL_D (0x4310 | REGS_SOUTH_TRANSCODER_PORT)
#define VLV_DP_AUX_CTL_B (VLV_DISPLAY_BASE + 0x64110)
#define VLV_DP_AUX_CTL_C (VLV_DISPLAY_BASE + 0x64210)
#define CHV_DP_AUX_CTL_D (VLV_DISPLAY_BASE + 0x64310)
#define INTEL_DP_AUX_CTL_BUSY (1 << 31)
#define INTEL_DP_AUX_CTL_DONE (1 << 30)
#define INTEL_DP_AUX_CTL_INTERRUPT (1 << 29)
#define INTEL_DP_AUX_CTL_TIMEOUT_ERROR (1 << 28)
#define INTEL_DP_AUX_CTL_TIMEOUT_400us (0 << 26)
#define INTEL_DP_AUX_CTL_TIMEOUT_600us (1 << 26)
#define INTEL_DP_AUX_CTL_TIMEOUT_800us (2 << 26)
#define INTEL_DP_AUX_CTL_TIMEOUT_1600us (3 << 26)
#define INTEL_DP_AUX_CTL_TIMEOUT_MASK (3 << 26)
#define INTEL_DP_AUX_CTL_RECEIVE_ERROR (1 << 25)
#define INTEL_DP_AUX_CTL_MSG_SIZE_MASK (0x1f << 20)
#define INTEL_DP_AUX_CTL_MSG_SIZE_SHIFT 20
#define INTEL_DP_AUX_CTL_PRECHARGE_2US_MASK (0xf << 16)
#define INTEL_DP_AUX_CTL_PRECHARGE_2US_SHIFT 16
#define INTEL_DP_AUX_CTL_BIT_CLOCK_2X_MASK (0x7ff)
#define INTEL_DP_AUX_CTL_BIT_CLOCK_2X_SHIFT 0
#define INTEL_DP_AUX_CTL_SYNC_PULSE_SKL(c) ((c) - 1)
// planes
#define INTEL_DISPLAY_A_PIPE_CONTROL (0x0008 | REGS_NORTH_PLANE_CONTROL)
#define INTEL_DISPLAY_B_PIPE_CONTROL (0x1008 | REGS_NORTH_PLANE_CONTROL)
#define DISPLAY_PIPE_ENABLED (1UL << 31)
#define INTEL_PIPE_ENABLED (1UL << 31)
#define INTEL_PIPE_CONTROL 0x0008
#define INTEL_PIPE_STATUS 0x0024
#define INTEL_PLANE_OFFSET 0x1000
#define INTEL_DISPLAY_A_PIPE_CONTROL (0x0008 | REGS_NORTH_PLANE_CONTROL)
#define INTEL_DISPLAY_B_PIPE_CONTROL (0x1008 | REGS_NORTH_PLANE_CONTROL)
#define INTEL_DISPLAY_A_PIPE_STATUS (0x0024 | REGS_NORTH_PLANE_CONTROL)
#define INTEL_DISPLAY_B_PIPE_STATUS (0x1024 | REGS_NORTH_PLANE_CONTROL)
#define DISPLAY_PIPE_VBLANK_ENABLED (1UL << 17)
#define DISPLAY_PIPE_VBLANK_STATUS (1UL << 1)
@@ -472,6 +631,7 @@ struct intel_free_graphics_memory {
#define INTEL_DISPLAY_B_SURFACE (0x119c | REGS_NORTH_PLANE_CONTROL)
// i965 and up only
// INTEL_DISPLAY_A_CONTROL source pixel format
#define DISPLAY_CONTROL_ENABLED (1UL << 31)
#define DISPLAY_CONTROL_GAMMA (1UL << 30)
#define DISPLAY_CONTROL_COLOR_MASK (0x0fUL << 26)
@@ -480,6 +640,19 @@ struct intel_free_graphics_memory {
#define DISPLAY_CONTROL_RGB16 (5UL << 26)
#define DISPLAY_CONTROL_RGB32 (6UL << 26)
// INTEL_DISPLAY_A_PIPE_CONTROL ILK+
#define INTEL_PIPE_DITHER_TYPE_MASK (0x0000000c)
#define INTEL_PIPE_DITHER_TYPE_SP (0 << 2)
#define INTEL_PIPE_DITHER_TYPE_ST1 (1 << 2)
#define INTEL_PIPE_DITHER_TYPE_ST2 (2 << 2)
#define INTEL_PIPE_DITHER_TYPE_TEMP (3 << 2)
#define INTEL_PIPE_DITHER_EN (1 << 4)
#define INTEL_PIPE_8BPC (0 << 5)
#define INTEL_PIPE_10BPC (1 << 5)
#define INTEL_PIPE_6BPC (2 << 5)
#define INTEL_PIPE_12BPC (3 << 5)
#define INTEL_PIPE_PROGRESSIVE (0 << 21)
// cursors
#define INTEL_CURSOR_CONTROL (0x0080 | REGS_NORTH_PLANE_CONTROL)
#define INTEL_CURSOR_BASE (0x0084 | REGS_NORTH_PLANE_CONTROL)
@@ -503,10 +676,13 @@ struct intel_free_graphics_memory {
// PLL registers
#define INTEL_DISPLAY_A_PLL (0x6014 | REGS_SOUTH_SHARED)
#define INTEL_DISPLAY_B_PLL (0x6018 | REGS_SOUTH_SHARED)
#define INTEL_DISPLAY_A_PLL_MULTIPLIER_DIVISOR \
(0x601c | REGS_SOUTH_SHARED)
#define INTEL_DISPLAY_B_PLL_MULTIPLIER_DIVISOR \
(0x6020 | REGS_SOUTH_SHARED)
#define CHV_DISPLAY_C_PLL (0x6030 | REGS_SOUTH_SHARED)
// Multiplier Divisor
#define INTEL_DISPLAY_A_PLL_MD (0x601C | REGS_SOUTH_SHARED)
#define INTEL_DISPLAY_B_PLL_MD (0x6020 | REGS_SOUTH_SHARED)
#define CHV_DISPLAY_B_PLL_MD (0x603C | REGS_SOUTH_SHARED)
#define INTEL_DISPLAY_A_PLL_DIVISOR_0 (0x6040 | REGS_SOUTH_SHARED)
#define INTEL_DISPLAY_A_PLL_DIVISOR_1 (0x6044 | REGS_SOUTH_SHARED)
#define INTEL_DISPLAY_B_PLL_DIVISOR_0 (0x6048 | REGS_SOUTH_SHARED)
@@ -535,23 +711,41 @@ struct intel_free_graphics_memory {
#define I2C_RESERVED ((1 << 13) | (1 << 5))
// TODO: on IronLake this is in the north shared block at 0x41000
#define INTEL_VGA_DISPLAY_CONTROL 0x71400
#define INTEL_VGA_DISPLAY_CONTROL (0x1400 | REGS_NORTH_PLANE_CONTROL)
#define VGA_DISPLAY_DISABLED (1UL << 31)
// LVDS panel
#define INTEL_PANEL_STATUS 0x61200
#define PANEL_STATUS_POWER_ON (1UL << 31)
#define INTEL_PANEL_CONTROL 0x61204
#define PANEL_CONTROL_POWER_TARGET_ON (1UL << 0)
#define INTEL_PANEL_FIT_CONTROL 0x61230
#define INTEL_PANEL_FIT_RATIOS 0x61234
#define INTEL_PANEL_STATUS (0x1200 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_PANEL_CONTROL (0x1204 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_PANEL_FIT_CONTROL (0x1230 | REGS_NORTH_PIPE_AND_PORT)
#define INTEL_PANEL_FIT_RATIOS (0x1234 | REGS_NORTH_PIPE_AND_PORT)
// LVDS on IronLake and up
#define PCH_PANEL_CONTROL 0xc7200
#define PCH_PANEL_STATUS 0xc7204
#define PANEL_REGISTER_UNLOCK (0xabcd << 16)
#define PCH_PANEL_STATUS (0x7200 | REGS_SOUTH_SHARED)
#define PCH_PANEL_CONTROL (0x7204 | REGS_SOUTH_SHARED)
#define PCH_PANEL_ON_DELAYS (0x7208 | REGS_SOUTH_SHARED)
#define PCH_PANEL_OFF_DELAYS (0x720c | REGS_SOUTH_SHARED)
#define PCH_PANEL_DIVISOR (0x7210 | REGS_SOUTH_SHARED)
#define PCH_LVDS_DETECTED (1 << 1)
#define PANEL_STATUS_POWER_ON (1UL << 31)
#define PANEL_CONTROL_POWER_TARGET_OFF (0UL << 0)
#define PANEL_CONTROL_POWER_TARGET_ON (1UL << 0)
#define PANEL_CONTROL_POWER_TARGET_RST (1UL << 1)
#define PANEL_REGISTER_UNLOCK (0xabcd << 16)
// PCH_PANEL_ON_DELAYS
#define PANEL_DELAY_PORT_SELECT_MASK (3 << 30)
#define PANEL_DELAY_PORT_SELECT_LVDS (0 << 30)
#define PANEL_DELAY_PORT_SELECT_DPA (1 << 30)
#define PANEL_DELAY_PORT_SELECT_DPC (2 << 30)
#define PANEL_DELAY_PORT_SELECT_DPD (3 << 30)
// PCH_PANEL_DIVISOR
#define PANEL_DIVISOR_REFERENCE_DIV_MASK 0xffffff00
#define PANEL_DIVISOR_REFERENCE_DIV_SHIFT 8
#define PANEL_DIVISOR_POW_CYCLE_DLY_MASK 0x1f
#define PANEL_DIVISOR_POW_CYCLE_DLY_SHIFT 0x1f
// ring buffer commands
@@ -594,6 +788,99 @@ struct intel_free_graphics_memory {
#define INTEL_OVERLAY_GAMMA_1 0x30020
#define INTEL_OVERLAY_GAMMA_0 0x30024
// FDI - Flexible Display Interface, the interface between the (CPU-internal)
// GPU and the PCH display outputs. Proprietary interface, based on DisplayPort
// though, so similar link training and all...
// There's an FDI transmitter (TX) on the CPU and an FDI receiver (RX) on the
// PCH for each display pipe.
// FDI receiver A is hooked up to transcoder A, FDI receiver B is hooked up to
// transcoder B, so we have the same mapping as with the display pipes.
#define PCH_FDI_RX_BASE_REGISTER 0xf0000
#define PCH_FDI_RX_PIPE_OFFSET 0x01000
#define PCH_FDI_RX_CONTROL 0x00c
#define FDI_RX_ENABLE (1 << 31)
#define FDI_RX_PLL_ENABLED (1 << 13)
#define FDI_FS_ERRC_ENABLE (1 << 27)
#define FDI_FE_ERRC_ENABLE (1 << 26)
#define PCH_FDI_RX_TRANS_UNIT_SIZE_1 0x30
#define PCH_FDI_RX_TRANS_UNIT_SIZE_2 0x38
#define FDI_RX_TRANS_UNIT_SIZE(x) ((x - 1) << 25)
#define FDI_RX_TRANS_UNIT_MASK 0x7e000000
#define FDI_RX_ENHANCE_FRAME_ENABLE (1 << 6)
#define FDI_RX_CLOCK_MASK (1 << 4)
#define FDI_RX_CLOCK_RAW (0 << 4)
#define FDI_RX_CLOCK_PCD (1 << 4)
#define PCH_FDI_TX_BASE_REGISTER 0x60000
#define PCH_FDI_TX_PIPE_OFFSET 0x01000
#define PCH_FDI_TX_CONTROL 0x100
#define FDI_TX_ENABLE (1 << 31)
#define FDI_TX_ENHANCE_FRAME_ENABLE (1 << 18)
#define FDI_TX_PLL_ENABLED (1 << 14)
#define FDI_PLL_BIOS_0 0x46000
#define FDI_PLL_FB_CLOCK_MASK 0xff
#define FDI_PLL_BIOS_1 0x46004
#define FDI_PLL_BIOS_2 0x46008
#define FDI_LINK_TRAIN_PATTERN_1 (0 << 28)
#define FDI_LINK_TRAIN_PATTERN_2 (1 << 28)
#define FDI_LINK_TRAIN_PATTERN_IDLE (2 << 28)
#define FDI_LINK_TRAIN_NONE (3 << 28)
#define FDI_LINK_TRAIN_VOLTAGE_0_4V (0 << 25)
#define FDI_LINK_TRAIN_VOLTAGE_0_6V (1 << 25)
#define FDI_LINK_TRAIN_VOLTAGE_0_8V (2 << 25)
#define FDI_LINK_TRAIN_VOLTAGE_1_2V (3 << 25)
#define FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0 << 22)
#define FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1 << 22)
#define FDI_LINK_TRAIN_PRE_EMPHASIS_2X (2 << 22)
#define FDI_LINK_TRAIN_PRE_EMPHASIS_3X (3 << 22)
#define FDI_AUTO_TRAINING (1 << 10)
#define FDI_AUTO_TRAIN_DONE (1 << 1)
// SNB A-stepping
#define FDI_LINK_TRAIN_400MV_0DB_SNB_A (0x38 << 22)
#define FDI_LINK_TRAIN_400MV_6DB_SNB_A (0x02 << 22)
#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_A (0x01 << 22)
#define FDI_LINK_TRAIN_800MV_0DB_SNB_A (0x00 << 22)
// SNB B-stepping
#define FDI_LINK_TRAIN_400MV_0DB_SNB_B (0x00 << 22)
#define FDI_LINK_TRAIN_400MV_6DB_SNB_B (0x3a << 22)
#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_B (0x39 << 22)
#define FDI_LINK_TRAIN_800MV_0DB_SNB_B (0x38 << 22)
#define FDI_LINK_TRAIN_VOL_EMP_MASK (0x3f << 22)
#define FDI_LINK_TRAIN_PATTERN_1_CPT (0 << 8)
#define FDI_LINK_TRAIN_PATTERN_2_CPT (1 << 8)
#define FDI_LINK_TRAIN_PATTERN_IDLE_CPT (2 << 8)
#define FDI_LINK_TRAIN_NORMAL_CPT (3 << 8)
#define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3 << 8)
// IvyBridge changes it up because... they hate developers?
#define FDI_LINK_TRAIN_PATTERN_1_IVB (0 << 8)
#define FDI_LINK_TRAIN_PATTERN_2_IVB (1 << 8)
#define FDI_LINK_TRAIN_PATTERN_IDLE_IVB (2 << 8)
#define FDI_LINK_TRAIN_NONE_IVB (3 << 8)
// CPU Panel Fitters - These are for IronLake and up and are the CPU internal
// panel fitters.
#define PCH_PANEL_FITTER_BASE_REGISTER 0x68000
#define PCH_PANEL_FITTER_PIPE_OFFSET 0x00800
#define PCH_PANEL_FITTER_WINDOW_POS 0x70
#define PCH_PANEL_FITTER_WINDOW_SIZE 0x74
#define PCH_PANEL_FITTER_CONTROL 0x80
#define PCH_PANEL_FITTER_V_SCALE 0x84
#define PCH_PANEL_FITTER_H_SCALE 0x90
#define PANEL_FITTER_ENABLED (1 << 31)
#define PANEL_FITTER_FILTER_MASK (3 << 23)
struct overlay_scale {
uint32 _reserved0 : 3;
uint32 horizontal_scale_fraction : 12;
@@ -768,7 +1055,7 @@ struct overlay_registers {
inline bool
intel_uses_physical_overlay(intel_shared_info &info)
{
return !info.device_type.InGroup(INTEL_TYPE_Gxx);
return !info.device_type.InGroup(INTEL_GROUP_Gxx);
}
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2012, Haiku, Inc. All Rights Reserved.
* Copyright 2012-2016, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@@ -13,12 +13,12 @@
#define TRACE_DISPLAY
#ifdef TRACE_DISPLAY
extern "C" void _sPrintf(const char* format, ...);
# define TRACE(x...) _sPrintf("radeon_hd: " x)
# define TRACE(x...) _sPrintf("dp_common: " x)
#else
# define TRACE(x...) ;
#endif
#define ERROR(x...) _sPrintf("radeon_hd: " x)
#define ERROR(x...) _sPrintf("dp_common: " x)
uint32
@@ -0,0 +1,364 @@
/*
* Copyright 2011-2015, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, [email protected]
* Alexander von Gluck IV, [email protected]
*/
#include "FlexibleDisplayInterface.h"
#include <stdlib.h>
#include <string.h>
#include <Debug.h>
#include <KernelExport.h>
#include "accelerant.h"
#include "intel_extreme.h"
#undef TRACE
#define TRACE_FDI
#ifdef TRACE_FDI
# define TRACE(x...) _sPrintf("intel_extreme: " x)
#else
# define TRACE(x...)
#endif
#define ERROR(x...) _sPrintf("intel_extreme: " x)
#define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
// #pragma mark - FDITransmitter
FDITransmitter::FDITransmitter(pipe_index pipeIndex)
:
fRegisterBase(PCH_FDI_TX_BASE_REGISTER)
{
if (pipeIndex == INTEL_PIPE_B)
fRegisterBase += PCH_FDI_TX_PIPE_OFFSET * 1;
}
FDITransmitter::~FDITransmitter()
{
}
void
FDITransmitter::Enable()
{
CALLED();
uint32 targetRegister = fRegisterBase + PCH_FDI_TX_CONTROL;
uint32 value = read32(targetRegister);
write32(targetRegister, value | FDI_TX_ENABLE);
read32(targetRegister);
spin(150);
}
void
FDITransmitter::Disable()
{
CALLED();
uint32 targetRegister = fRegisterBase + PCH_FDI_TX_CONTROL;
uint32 value = read32(targetRegister);
write32(targetRegister, value & ~FDI_TX_ENABLE);
read32(targetRegister);
spin(150);
}
bool
FDITransmitter::IsPLLEnabled()
{
CALLED();
return (read32(fRegisterBase + PCH_FDI_TX_CONTROL) & FDI_TX_PLL_ENABLED)
!= 0;
}
void
FDITransmitter::EnablePLL()
{
CALLED();
uint32 targetRegister = fRegisterBase + PCH_FDI_TX_CONTROL;
uint32 value = read32(targetRegister);
if ((value & FDI_TX_PLL_ENABLED) != 0) {
// already enabled, possibly IronLake where it always is
return;
}
write32(targetRegister, value | FDI_TX_PLL_ENABLED);
read32(targetRegister);
spin(100); // warmup 10us + dmi delay 20us, be generous
}
void
FDITransmitter::DisablePLL()
{
CALLED();
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_ILK)) {
// on IronLake the FDI PLL is alaways enabled, so no point in trying...
return;
}
uint32 targetRegister = fRegisterBase + PCH_FDI_TX_CONTROL;
write32(targetRegister, read32(targetRegister) & ~FDI_TX_PLL_ENABLED);
read32(targetRegister);
spin(100);
}
// #pragma mark - FDIReceiver
FDIReceiver::FDIReceiver(pipe_index pipeIndex)
:
fRegisterBase(PCH_FDI_RX_BASE_REGISTER)
{
if (pipeIndex == INTEL_PIPE_B)
fRegisterBase += PCH_FDI_RX_PIPE_OFFSET * 1;
}
FDIReceiver::~FDIReceiver()
{
}
void
FDIReceiver::Enable()
{
CALLED();
uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL;
uint32 value = read32(targetRegister);
write32(targetRegister, value | FDI_RX_ENABLE);
read32(targetRegister);
spin(150);
}
void
FDIReceiver::Disable()
{
CALLED();
uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL;
uint32 value = read32(targetRegister);
write32(targetRegister, value & ~FDI_RX_ENABLE);
read32(targetRegister);
spin(150);
}
bool
FDIReceiver::IsPLLEnabled()
{
CALLED();
return (read32(fRegisterBase + PCH_FDI_RX_CONTROL) & FDI_RX_PLL_ENABLED)
!= 0;
}
void
FDIReceiver::EnablePLL()
{
CALLED();
uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL;
uint32 value = read32(targetRegister);
if ((value & FDI_RX_PLL_ENABLED) != 0)
return;
write32(targetRegister, value | FDI_RX_PLL_ENABLED);
read32(targetRegister);
spin(200); // warmup 10us + dmi delay 20us, be generous
}
void
FDIReceiver::DisablePLL()
{
CALLED();
uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL;
write32(targetRegister, read32(targetRegister) & ~FDI_RX_PLL_ENABLED);
read32(targetRegister);
spin(100);
}
void
FDIReceiver::SwitchClock(bool toPCDClock)
{
CALLED();
uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL;
write32(targetRegister, (read32(targetRegister) & ~FDI_RX_CLOCK_MASK)
| (toPCDClock ? FDI_RX_CLOCK_PCD : FDI_RX_CLOCK_RAW));
read32(targetRegister);
spin(200);
}
// #pragma mark - FDILink
FDILink::FDILink(pipe_index pipeIndex)
:
fTransmitter(pipeIndex),
fReceiver(pipeIndex)
{
}
status_t
FDILink::Train(display_mode* target)
{
CALLED();
uint32 bitsPerPixel;
switch (target->space) {
case B_RGB32_LITTLE:
bitsPerPixel = 32;
break;
case B_RGB16_LITTLE:
bitsPerPixel = 16;
break;
case B_RGB15_LITTLE:
bitsPerPixel = 15;
break;
case B_CMAP8:
default:
bitsPerPixel = 8;
break;
}
// Khz / 10. ( each output octet encoded as 10 bits.
uint32 linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10;
uint32 bps = target->timing.pixel_clock * bitsPerPixel * 21 / 20;
uint32 lanes = bps / (linkBandwidth * 8);
TRACE("%s: FDI Link Lanes: %" B_PRIu32 "\n", __func__, lanes);
// Enable FDI clocks
Receiver().EnablePLL();
Receiver().SwitchClock(true);
Transmitter().EnablePLL();
status_t result = B_ERROR;
// Over IVB supports AutoTraining of FDI
if (gInfo->shared_info->device_type.Generation() >= 7) {
result = _AutoTrain(lanes);
if (result != B_OK) {
ERROR("%s: FDI auto-training fault. Attempting manual train.\n",
__func__);
return _ManualTrain(lanes);
}
return B_OK;
}
return _ManualTrain(lanes);
}
status_t
FDILink::_ManualTrain(uint32 lanes)
{
CALLED();
// This needs completed
ERROR("TODO: Manual FDI Link Training\n");
// Enable pipes
Transmitter().Enable();
Receiver().Enable();
return B_OK;
}
status_t
FDILink::_AutoTrain(uint32 lanes)
{
CALLED();
uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL;
uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL;
uint32 buffer = read32(txControl);
// Clear port width selection and set number of lanes
buffer &= ~(7 << 19);
buffer |= (lanes - 1) << 19;
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB))
buffer &= ~FDI_LINK_TRAIN_NONE_IVB;
else
buffer &= ~FDI_LINK_TRAIN_NONE;
write32(txControl, buffer);
static const int snb_b_fdi_train_param[] = {
FDI_LINK_TRAIN_400MV_0DB_SNB_B,
FDI_LINK_TRAIN_400MV_6DB_SNB_B,
FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
FDI_LINK_TRAIN_800MV_0DB_SNB_B,
};
bool trained = false;
for (uint32 i = 0; i < (sizeof(snb_b_fdi_train_param)
/ sizeof(snb_b_fdi_train_param[0])); i++) {
for (int j = 0; j < 2; j++) {
buffer = read32(txControl);
buffer |= FDI_AUTO_TRAINING;
buffer &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
buffer |= snb_b_fdi_train_param[i];
write32(txControl, buffer | FDI_TX_ENABLE);
write32(rxControl, read32(rxControl) | FDI_RX_ENABLE);
spin(5);
buffer = read32(txControl);
if ((buffer & FDI_AUTO_TRAIN_DONE) != 0) {
TRACE("%s: FDI auto train complete!\n", __func__);
trained = true;
break;
}
write32(txControl, read32(txControl) & ~FDI_TX_ENABLE);
write32(rxControl, read32(rxControl) & ~FDI_RX_ENABLE);
read32(rxControl);
spin(31);
}
// If Trained, we fall out of autotraining
if (trained)
break;
}
if (!trained) {
ERROR("%s: FDI auto train failed!\n", __func__);
return B_ERROR;
}
// Enable ecc on IVB
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) {
write32(rxControl, read32(rxControl)
| FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE);
read32(rxControl);
}
return B_OK;
}
FDILink::~FDILink()
{
}
@@ -0,0 +1,79 @@
/*
* Copyright 2011-2015, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, [email protected]
* Alexander von Gluck IV, [email protected]
*/
#ifndef INTEL_FDI_H
#define INTEL_FDI_H
#include "intel_extreme.h"
class FDITransmitter {
public:
FDITransmitter(pipe_index pipeIndex);
~FDITransmitter();
void Enable();
void Disable();
bool IsPLLEnabled();
void EnablePLL();
void DisablePLL();
uint32 Base()
{ return fRegisterBase; };
private:
uint32 fRegisterBase;
};
class FDIReceiver {
public:
FDIReceiver(pipe_index pipeIndex);
~FDIReceiver();
void Enable();
void Disable();
bool IsPLLEnabled();
void EnablePLL();
void DisablePLL();
void SwitchClock(bool toPCDClock);
uint32 Base()
{ return fRegisterBase; };
protected:
uint32 fRegisterBase;
};
class FDILink {
public:
FDILink(pipe_index pipeIndex);
~FDILink();
FDITransmitter& Transmitter()
{ return fTransmitter; };
FDIReceiver& Receiver()
{ return fReceiver; };
status_t Train(display_mode* target);
private:
status_t _ManualTrain(uint32 lanes);
status_t _AutoTrain(uint32 lanes);
FDITransmitter fTransmitter;
FDIReceiver fReceiver;
};
#endif // INTEL_FDI_H
@@ -16,5 +16,11 @@ Addon intel_extreme.accelerant :
mode.cpp
overlay.cpp
# overlay_3d_i965.cpp
: be libaccelerantscommon.a
pll.cpp
# classes
FlexibleDisplayInterface.cpp
# PanelFitter.cpp
Ports.cpp
Pipes.cpp
: be $(TARGET_LIBSTDC++) libaccelerantscommon.a
;
@@ -0,0 +1,72 @@
/*
* Copyright 2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, [email protected]
*/
#include "PanelFitter.h"
#include "accelerant.h"
#include "intel_extreme.h"
#include <stdlib.h>
#include <string.h>
#undef TRACE
#define TRACE_FITTER
#ifdef TRACE_FITTER
# define TRACE(x...) _sPrintf("intel_extreme: " x)
#else
# define TRACE(x...)
#endif
#define ERROR(x...) _sPrintf("intel_extreme: " x)
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
// #pragma mark - PanelFitter
PanelFitter::PanelFitter(int32 pipeIndex)
:
fBaseRegister(PCH_PANEL_FITTER_BASE_REGISTER
+ pipeIndex * PCH_PANEL_FITTER_PIPE_OFFSET)
{
}
bool
PanelFitter::IsEnabled()
{
return (read32(fBaseRegister + PCH_PANEL_FITTER_CONTROL)
& PANEL_FITTER_ENABLED) != 0;
}
void
PanelFitter::Enable(const display_mode& mode)
{
// TODO: program the right window size and position based on the mode
_Enable(true);
}
void
PanelFitter::Disable()
{
_Enable(false);
}
void
PanelFitter::_Enable(bool enable)
{
uint32 targetRegister = fBaseRegister + PCH_PANEL_FITTER_CONTROL;
write32(targetRegister, read32(targetRegister) & ~PANEL_FITTER_ENABLED
| (enable ? PANEL_FITTER_ENABLED | 0));
read32(targetRegister);
}
@@ -0,0 +1,27 @@
/*
* Copyright 2011, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, mmlr@mlotz.ch
*/
#ifndef INTEL_FITTER_H
#define INTEL_FITTER_H
class PanelFitter {
public:
PanelFitter(int32 pipeIndex);
virtual ~PanelFitter();
bool IsEnabled();
void Enable(const display_mode& mode);
void Disable();
private:
void _Enable(bool enable);
uint32 fRegisterBase;
};
#endif // INTEL_FITTER_H
@@ -0,0 +1,335 @@
/*
* Copyright 2011-2015, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, mmlr@mlotz.ch
* Alexander von Gluck IV, kallisti5@unixzen.com
*/
#include "Pipes.h"
#include "accelerant.h"
#include "intel_extreme.h"
#include <KernelExport.h>
#include <stdlib.h>
#include <string.h>
#include <new>
#define TRACE_PIPE
#ifdef TRACE_PIPE
extern "C" void _sPrintf(const char* format, ...);
# define TRACE(x...) _sPrintf("intel_extreme: " x)
#else
# define TRACE(x...) ;
#endif
#define ERROR(x...) _sPrintf("intel_extreme: " x)
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
// PIPE: 6
// PLANE: 7
void
program_pipe_color_modes(uint32 colorMode)
{
// All pipes get the same color mode
write32(INTEL_DISPLAY_A_CONTROL, (read32(INTEL_DISPLAY_A_CONTROL)
& ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA))
| colorMode);
write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL)
& ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA))
| colorMode);
}
// #pragma mark - Pipe
Pipe::Pipe(pipe_index pipeIndex)
:
fHasTranscoder(false),
fFDILink(NULL),
// fPanelFitter(NULL),
fPipeIndex(pipeIndex),
fPipeOffset(0),
fPlaneOffset(0)
{
if (pipeIndex == INTEL_PIPE_B) {
fPipeOffset = INTEL_DISPLAY_OFFSET;
fPlaneOffset = INTEL_PLANE_OFFSET;
}
if (gInfo->shared_info->device_type.HasPlatformControlHub()) {
fHasTranscoder = true;
// Program FDILink if PCH
if (fFDILink == NULL)
fFDILink = new(std::nothrow) FDILink(pipeIndex);
}
TRACE("Pipe %s. Pipe Base: 0x%" B_PRIxADDR
" Plane Base: 0x% " B_PRIxADDR "\n", (pipeIndex == INTEL_PIPE_A)
? "A" : "B", fPipeOffset, fPlaneOffset);
}
Pipe::~Pipe()
{
}
bool
Pipe::IsEnabled()
{
CALLED();
return (read32(INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset)
& INTEL_PIPE_ENABLED) != 0;
}
void
Pipe::Configure(display_mode* mode)
{
uint32 pipeControl = read32(INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset);
// TODO: Haswell+ dithering changes.
if (gInfo->shared_info->device_type.Generation() >= 4) {
pipeControl |= (INTEL_PIPE_DITHER_EN | INTEL_PIPE_DITHER_TYPE_SP);
switch (mode->space) {
case B_CMAP8:
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
pipeControl |= INTEL_PIPE_6BPC;
break;
case B_RGB24_LITTLE:
pipeControl |= INTEL_PIPE_8BPC;
break;
case B_RGB32_LITTLE:
default:
pipeControl |= INTEL_PIPE_10BPC;
break;
}
}
// TODO: CxSR downclocking?
// TODO: Interlaced modes
pipeControl |= INTEL_PIPE_PROGRESSIVE;
write32(INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset, pipeControl);
read32(INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset);
}
void
Pipe::_ConfigureTranscoder(display_mode* target)
{
// update timing (fPipeOffset bumps the DISPLAY_A to B when needed)
write32(INTEL_TRANSCODER_A_HTOTAL + fPipeOffset,
((uint32)(target->timing.h_total - 1) << 16)
| ((uint32)target->timing.h_display - 1));
write32(INTEL_TRANSCODER_A_HBLANK + fPipeOffset,
((uint32)(target->timing.h_total - 1) << 16)
| ((uint32)target->timing.h_display - 1));
write32(INTEL_TRANSCODER_A_HSYNC + fPipeOffset,
((uint32)(target->timing.h_sync_end - 1) << 16)
| ((uint32)target->timing.h_sync_start - 1));
write32(INTEL_TRANSCODER_A_VTOTAL + fPipeOffset,
((uint32)(target->timing.v_total - 1) << 16)
| ((uint32)target->timing.v_display - 1));
write32(INTEL_TRANSCODER_A_VBLANK + fPipeOffset,
((uint32)(target->timing.v_total - 1) << 16)
| ((uint32)target->timing.v_display - 1));
write32(INTEL_TRANSCODER_A_VSYNC + fPipeOffset,
((uint32)(target->timing.v_sync_end - 1) << 16)
| ((uint32)target->timing.v_sync_start - 1));
#if 0
// XXX: Is it ok to do these on non-digital?
write32(INTEL_TRANSCODER_A_POS + fPipeOffset, 0);
write32(INTEL_TRANSCODER_A_IMAGE_SIZE + fPipeOffset,
((uint32)(target->virtual_width - 1) << 16)
| ((uint32)target->virtual_height - 1));
#endif
}
void
Pipe::ConfigureTimings(display_mode* target)
{
CALLED();
if (target == NULL) {
ERROR("%s: Invalid display mode!\n", __func__);
return;
}
// update timing (fPipeOffset bumps the DISPLAY_A to B when needed)
write32(INTEL_DISPLAY_A_HTOTAL + fPipeOffset,
((uint32)(target->timing.h_total - 1) << 16)
| ((uint32)target->timing.h_display - 1));
write32(INTEL_DISPLAY_A_HBLANK + fPipeOffset,
((uint32)(target->timing.h_total - 1) << 16)
| ((uint32)target->timing.h_display - 1));
write32(INTEL_DISPLAY_A_HSYNC + fPipeOffset,
((uint32)(target->timing.h_sync_end - 1) << 16)
| ((uint32)target->timing.h_sync_start - 1));
write32(INTEL_DISPLAY_A_VTOTAL + fPipeOffset,
((uint32)(target->timing.v_total - 1) << 16)
| ((uint32)target->timing.v_display - 1));
write32(INTEL_DISPLAY_A_VBLANK + fPipeOffset,
((uint32)(target->timing.v_total - 1) << 16)
| ((uint32)target->timing.v_display - 1));
write32(INTEL_DISPLAY_A_VSYNC + fPipeOffset,
((uint32)(target->timing.v_sync_end - 1) << 16)
| ((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)
| ((uint32)target->virtual_height - 1));
write32(INTEL_DISPLAY_A_PIPE_SIZE + fPipeOffset,
((uint32)(target->timing.v_display - 1) << 16)
| ((uint32)target->timing.h_display - 1));
// This is useful for debugging: it sets the border to red, so you
// can see what is border and what is porch (black area around the
// sync)
//write32(INTEL_DISPLAY_A_RED + fPipeOffset, 0x00FF0000);
if (fHasTranscoder)
_ConfigureTranscoder(target);
}
void
Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock,
uint32 extraFlags)
{
CALLED();
addr_t pllDivisorA = INTEL_DISPLAY_A_PLL_DIVISOR_0;
addr_t pllDivisorB = INTEL_DISPLAY_A_PLL_DIVISOR_1;
addr_t pllControl = INTEL_DISPLAY_A_PLL;
addr_t pllMD = INTEL_DISPLAY_A_PLL_MD;
if (fPipeIndex == INTEL_PIPE_B) {
pllDivisorA = INTEL_DISPLAY_B_PLL_DIVISOR_0;
pllDivisorB = INTEL_DISPLAY_B_PLL_DIVISOR_1;
pllControl = INTEL_DISPLAY_B_PLL;
pllMD = INTEL_DISPLAY_B_PLL_MD;
}
float refFreq = gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x)) {
float adjusted = ((refFreq * divisors.m) / divisors.n) / divisors.post;
uint32 pixelMultiply = uint32(adjusted / (pixelClock / 1000.0f));
write32(pllMD, (0 << 24) | ((pixelMultiply - 1) << 8));
}
// XXX: For now we assume no LVDS downclocking and program the same divisor
// value to both divisor 0 (standard) and 1 (reduced divisor)
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) {
write32(pllDivisorA, (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_N_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
write32(pllDivisorB, (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_N_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
} else {
write32(pllDivisorA, (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_N_DIVISOR_MASK)
| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
& DISPLAY_PLL_M1_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_M2_DIVISOR_MASK));
write32(pllDivisorB, (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_N_DIVISOR_MASK)
| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
& DISPLAY_PLL_M1_DIVISOR_MASK)
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_M2_DIVISOR_MASK));
}
uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL | extraFlags;
if (gInfo->shared_info->device_type.Generation() >= 3) {
// post1 divisor << 1 , 1-8
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) {
pll |= ((1 << (divisors.post1 - 1))
<< DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_POST1_DIVISOR_MASK;
} else {
pll |= ((1 << (divisors.post1 - 1))
<< DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
// pll |= ((divisors.post1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
// & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK;
}
// p2 clock divider. 5 or 7 high
if (divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_HIGH;
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x))
pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT;
} else {
if (!divisors.post2_high)
pll |= DISPLAY_PLL_DIVIDE_4X;
pll |= DISPLAY_PLL_2X_CLOCK;
// TODO: Is this supposed to be DISPLAY_PLL_IGD_POST1_DIVISOR_MASK??
if (divisors.post1 > 2) {
pll |= ((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT)
& DISPLAY_PLL_POST1_DIVISOR_MASK;
} else
pll |= DISPLAY_PLL_POST1_DIVIDE_2;
}
// Allow the PLL to warm up by masking its bit.
write32(pllControl, pll & ~DISPLAY_PLL_NO_VGA_CONTROL);
read32(pllControl);
spin(150);
write32(pllControl, pll);
read32(pllControl);
spin(150);
}
void
Pipe::Enable(bool enable)
{
CALLED();
addr_t pipeReg = INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset;
addr_t planeReg = INTEL_DISPLAY_A_CONTROL + fPlaneOffset;
// Planes always have to operate on an enabled pipe
if (enable) {
write32(pipeReg, read32(pipeReg) | INTEL_PIPE_ENABLED);
wait_for_vblank();
write32(planeReg, read32(planeReg) | DISPLAY_CONTROL_ENABLED);
} else {
write32(planeReg, read32(planeReg) & ~DISPLAY_CONTROL_ENABLED);
wait_for_vblank();
write32(pipeReg, read32(pipeReg) & ~INTEL_PIPE_ENABLED);
}
read32(INTEL_DISPLAY_A_BASE);
// flush the eventually cached PCI bus writes
}
@@ -0,0 +1,69 @@
/*
* Copyright 2011-2015, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, mmlr@mlotz.ch
* Alexander von Gluck IV, kallisti5@unixzen.com
*/
#ifndef INTEL_PIPE_H
#define INTEL_PIPE_H
#include <edid.h>
#include "intel_extreme.h"
#include "pll.h"
#include "FlexibleDisplayInterface.h"
#define MAX_PIPES 2
void program_pipe_color_modes(uint32 colorMode);
//class FDILink;
//class PanelFitter;
class Pipe {
public:
Pipe(pipe_index pipeIndex);
~Pipe();
pipe_index Index()
{ return fPipeIndex; }
bool IsEnabled();
void Enable(bool enable);
void Disable();
void Configure(display_mode* mode);
void ConfigureTimings(display_mode* mode);
void ConfigureClocks(
const pll_divisors& divisors,
uint32 pixelClock,
uint32 extraFlags);
// access to the various parts of the pipe
::FDILink* FDI()
{ return fFDILink; }
// ::PanelFitter* PanelFitter()
// { return fPanelFitter; }
private:
void _ConfigureTranscoder(display_mode* mode);
bool fHasTranscoder;
FDILink* fFDILink;
// PanelFitter* fPanelFitter;
pipe_index fPipeIndex;
addr_t fPipeOffset;
addr_t fPlaneOffset;
};
#endif // INTEL_PIPE_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,225 @@
/*
* Copyright 2011-2015, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz, mmlr@mlotz.ch
* Alexander von Gluck IV, kallisti5@unixzen.com
*/
#ifndef INTEL_PORTS_H
#define INTEL_PORTS_H
#include <edid.h>
#include "intel_extreme.h"
#include "Pipes.h"
#include "pll.h"
#define MAX_PORTS 20 // a generous upper bound
struct pll_limits;
enum port_type {
INTEL_PORT_TYPE_ANY, // wildcard for lookup functions
INTEL_PORT_TYPE_ANALOG,
INTEL_PORT_TYPE_DVI,
INTEL_PORT_TYPE_LVDS,
INTEL_PORT_TYPE_DP,
INTEL_PORT_TYPE_eDP,
INTEL_PORT_TYPE_HDMI
};
enum port_index {
INTEL_PORT_ANY, // wildcard for lookup functions
INTEL_PORT_A,
INTEL_PORT_B,
INTEL_PORT_C,
INTEL_PORT_D
};
class Port {
public:
Port(port_index index,
const char* baseName);
virtual ~Port();
virtual uint32 Type() const = 0;
const char* PortName() const
{ return fPortName; }
port_index PortIndex() const
{ return fPortIndex; }
virtual bool IsConnected() = 0;
status_t SetPipe(Pipe* pipe);
::Pipe* GetPipe()
{ return fPipe; };
virtual status_t Power(bool enabled);
bool HasEDID();
virtual status_t GetEDID(edid1_info* edid,
bool forceRead = false);
virtual status_t GetPLLLimits(pll_limits& limits);
virtual status_t SetDisplayMode(display_mode* mode,
uint32 colorMode) { return B_ERROR; };
virtual pipe_index PipePreference()
{ return INTEL_PIPE_ANY; };
protected:
void _SetName(const char* name);
static status_t _GetI2CSignals(void* cookie, int* _clock,
int* _data);
static status_t _SetI2CSignals(void* cookie, int clock,
int data);
display_mode fCurrentMode;
Pipe* fPipe;
private:
virtual addr_t _DDCRegister() = 0;
virtual addr_t _PortRegister() = 0;
port_index fPortIndex;
char* fPortName;
status_t fEDIDState;
edid1_info fEDIDInfo;
};
class AnalogPort : public Port {
public:
AnalogPort();
virtual uint32 Type() const
{ return INTEL_PORT_TYPE_ANALOG; }
virtual bool IsConnected();
virtual status_t SetDisplayMode(display_mode* mode,
uint32 colorMode);
protected:
virtual addr_t _DDCRegister();
virtual addr_t _PortRegister();
};
class LVDSPort : public Port {
public:
LVDSPort();
virtual uint32 Type() const
{ return INTEL_PORT_TYPE_LVDS; }
virtual bool IsConnected();
virtual status_t SetDisplayMode(display_mode* mode,
uint32 colorMode);
virtual pipe_index PipePreference()
{ return INTEL_PIPE_B; };
protected:
virtual addr_t _DDCRegister();
virtual addr_t _PortRegister();
};
class DigitalPort : public Port {
public:
DigitalPort(
port_index index = INTEL_PORT_B,
const char* baseName = "DVI");
virtual uint32 Type() const
{ return INTEL_PORT_TYPE_DVI; }
virtual bool IsConnected();
virtual status_t SetDisplayMode(display_mode* mode,
uint32 colorMode);
protected:
virtual addr_t _DDCRegister();
virtual addr_t _PortRegister();
};
class HDMIPort : public DigitalPort {
public:
HDMIPort(port_index index);
virtual uint32 Type() const
{ return INTEL_PORT_TYPE_HDMI; }
virtual bool IsConnected();
protected:
virtual addr_t _PortRegister();
};
class DisplayPort : public Port {
public:
DisplayPort(port_index index,
const char* baseName = "DisplayPort");
virtual uint32 Type() const
{ return INTEL_PORT_TYPE_DP; }
virtual bool IsConnected();
virtual status_t SetDisplayMode(display_mode* mode,
uint32 colorMode);
protected:
virtual addr_t _DDCRegister();
virtual addr_t _PortRegister();
};
class EmbeddedDisplayPort : public DisplayPort {
public:
EmbeddedDisplayPort();
virtual uint32 Type() const
{ return INTEL_PORT_TYPE_eDP; }
virtual bool IsConnected();
};
class DigitalDisplayInterface : public Port {
public:
DigitalDisplayInterface(
port_index index = INTEL_PORT_A,
const char* baseName = "Digital Display Interface");
virtual uint32 Type() const
{ return INTEL_PORT_TYPE_DVI; }
virtual status_t Power(bool enabled);
virtual bool IsConnected();
virtual status_t SetDisplayMode(display_mode* mode,
uint32 colorMode);
protected:
virtual addr_t _DDCRegister();
virtual addr_t _PortRegister();
};
#endif // INTEL_PORTS_H
@@ -19,22 +19,25 @@
#include <unistd.h>
#include <syslog.h>
#include <new>
#include <AGP.h>
#undef TRACE
#define TRACE_ACCELERANT
#ifdef TRACE_ACCELERANT
# define TRACE(x...) _sPrintf("intel_extreme accelerant:" x)
# define TRACE(x...) _sPrintf("intel_extreme: " x)
#else
# define TRACE(x...)
#endif
#define ERROR(x...) _sPrintf("intel_extreme accelerant: " x)
#define ERROR(x...) _sPrintf("intel_extreme: " x)
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
struct accelerant_info* gInfo;
uint32 gDumpCount;
class AreaCloner {
@@ -87,6 +90,36 @@ AreaCloner::Keep()
// #pragma mark -
// intel_reg --mmio=ie-0001.bin --devid=27a2 dump
void
dump_registers()
{
char filename[255];
sprintf(filename, "/boot/system/cache/tmp/ie-%04" B_PRId32 ".bin",
gDumpCount);
ERROR("%s: Taking register dump #%" B_PRId32 "\n", __func__, gDumpCount);
int fd = open(filename, O_CREAT | O_WRONLY, 0644);
uint32 data = 0;
if (fd >= 0) {
for (int32 i = 0; i < 0x80000; i += sizeof(data)) {
//char line[512];
//int length = sprintf(line, "%05" B_PRIx32 ": "
// "%08" B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32 "\n",
// i, read32(i), read32(i + 4), read32(i + 8), read32(i + 12));
data = read32(i);
write(fd, &data, sizeof(data));
}
close(fd);
sync();
}
gDumpCount++;
}
/*! This is the common accelerant_info initializer. It is called by
both, the first accelerant and all clones.
*/
@@ -95,6 +128,9 @@ init_common(int device, bool isClone)
{
// initialize global accelerant info structure
// Number of register dumps we have... taken.
gDumpCount = 0;
gInfo = (accelerant_info*)malloc(sizeof(accelerant_info));
if (gInfo == NULL)
return B_NO_MEMORY;
@@ -147,7 +183,7 @@ init_common(int device, bool isClone)
+ gInfo->shared_info->overlay_offset);
}
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) {
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x)) {
// allocate some extra memory for the 3D context
if (intel_allocate_memory(INTEL_i965_3D_CONTEXT_SIZE,
B_APERTURE_NON_RESERVED, gInfo->context_base) == B_OK) {
@@ -156,6 +192,26 @@ init_common(int device, bool isClone)
}
}
gInfo->pipe_count = 0;
// Allocate all of our pipes
for (int i = 0; i < MAX_PIPES; i++) {
switch (i) {
case 0:
gInfo->pipes[i] = new(std::nothrow) Pipe(INTEL_PIPE_A);
break;
case 1:
gInfo->pipes[i] = new(std::nothrow) Pipe(INTEL_PIPE_B);
break;
default:
ERROR("%s: Unknown pipe %d\n", __func__, i);
}
if (gInfo->pipes[i] == NULL)
ERROR("%s: Error allocating pipe %d\n", __func__, i);
else
gInfo->pipe_count++;
}
return B_OK;
}
@@ -179,6 +235,200 @@ uninit_common(void)
}
static void
dump_ports()
{
if (gInfo->port_count == 0) {
TRACE("%s: No ports connected\n", __func__);
return;
}
TRACE("%s: Connected ports: (port_count: %" B_PRIu32 ")\n", __func__,
gInfo->port_count);
for (uint32 i = 0; i < gInfo->port_count; i++) {
Port* port = gInfo->ports[i];
if (!port) {
TRACE("port %" B_PRIu32 ":: INVALID ALLOC!\n", i);
continue;
}
TRACE("port %" B_PRIu32 ": %s %s\n", i, port->PortName(),
port->IsConnected() ? "connected" : "disconnected");
}
}
static bool
has_connected_port(port_index portIndex, uint32 type)
{
for (uint32 i = 0; i < gInfo->port_count; i++) {
Port* port = gInfo->ports[i];
if (type != INTEL_PORT_TYPE_ANY && port->Type() != type)
continue;
if (portIndex != INTEL_PORT_ANY && port->PortIndex() != portIndex)
continue;
return true;
}
return false;
}
static status_t
probe_ports()
{
// Try to determine what ports to use. We use the following heuristic:
// * Check for DisplayPort, these can be more or less detected reliably.
// * Check for HDMI, it'll fail on devices not having HDMI for us to fall
// back to DVI.
// * Assume DVI B if no HDMI and no DisplayPort is present, confirmed by
// reading EDID in the IsConnected() call.
// * Check for analog if possible (there's a detection bit on PCH),
// otherwise the assumed presence is confirmed by reading EDID in
// IsConnected().
TRACE("adpa: %08" B_PRIx32 "\n", read32(INTEL_ANALOG_PORT));
TRACE("dova: %08" B_PRIx32 ", dovb: %08" B_PRIx32
", dovc: %08" B_PRIx32 "\n", read32(INTEL_DIGITAL_PORT_A),
read32(INTEL_DIGITAL_PORT_B), read32(INTEL_DIGITAL_PORT_C));
TRACE("lvds: %08" B_PRIx32 "\n", read32(INTEL_DIGITAL_LVDS_PORT));
gInfo->port_count = 0;
for (int i = INTEL_PORT_A; i <= INTEL_PORT_D; i++) {
Port* displayPort = new(std::nothrow) DisplayPort((port_index)i);
if (displayPort == NULL)
return B_NO_MEMORY;
if (displayPort->IsConnected())
gInfo->ports[gInfo->port_count++] = displayPort;
else
delete displayPort;
}
// Digital Display Interface
if (gInfo->shared_info->device_type.HasDDI()) {
for (int i = INTEL_PORT_A; i <= INTEL_PORT_B; i++) {
Port* ddiPort
= new(std::nothrow) DigitalDisplayInterface((port_index)i);
if (ddiPort == NULL)
return B_NO_MEMORY;
if (ddiPort->IsConnected())
gInfo->ports[gInfo->port_count++] = ddiPort;
else
delete ddiPort;
}
}
// Ensure DP_A isn't already taken (or DDI)
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
Port* eDPPort = new(std::nothrow) EmbeddedDisplayPort();
if (eDPPort == NULL)
return B_NO_MEMORY;
if (eDPPort->IsConnected())
gInfo->ports[gInfo->port_count++] = eDPPort;
else
delete eDPPort;
}
for (int i = INTEL_PORT_B; i <= INTEL_PORT_D; i++) {
if (has_connected_port((port_index)i, INTEL_PORT_TYPE_ANY)) {
// Ensure port not already claimed by something like DDI
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;
}
if (!has_connected_port(INTEL_PORT_ANY, INTEL_PORT_TYPE_ANY)) {
// there's neither DisplayPort nor HDMI so far, assume DVI B
Port* dviPort = new(std::nothrow) DigitalPort(INTEL_PORT_B);
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;
}
// always try the LVDS port, it'll simply fail if not applicable
Port* lvdsPort = new(std::nothrow) LVDSPort();
if (lvdsPort == NULL)
return B_NO_MEMORY;
if (lvdsPort->IsConnected()) {
gInfo->ports[gInfo->port_count++] = lvdsPort;
gInfo->head_mode |= HEAD_MODE_LVDS_PANEL;
gInfo->head_mode |= HEAD_MODE_B_DIGITAL;
} else
delete lvdsPort;
// then finally always try the analog port
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;
return B_OK;
}
static status_t
assign_pipes()
{
// TODO: At some point we should "group" ports to pipes with the same mode.
// You can drive multiple ports from a single pipe as long as the mode is
// the same. For the moment we could get displays with the wrong pipes
// assigned when the count is > 1;
uint32 current = 0;
for (uint32 i = 0; i < gInfo->port_count; i++) {
if (gInfo->ports[i] == NULL)
continue;
pipe_index preference = gInfo->ports[i]->PipePreference();
if (preference != INTEL_PIPE_ANY) {
// Some ports *really* need to be assigned a pipe due to
// implementation bugs.
int index = (preference == INTEL_PIPE_B) ? 1 : 0;
gInfo->ports[i]->SetPipe(gInfo->pipes[index]);
continue;
}
if (gInfo->ports[i]->IsConnected()) {
if (current >= gInfo->pipe_count) {
ERROR("%s: No pipes left to assign to port %s!\n", __func__,
gInfo->ports[i]->PortName());
continue;
}
gInfo->ports[i]->SetPipe(gInfo->pipes[current]);
current++;
}
}
return B_OK;
}
// #pragma mark - public accelerant functions
@@ -199,36 +449,22 @@ intel_init_accelerant(int device)
setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer");
// determine head depending on what's already enabled from the BIOS
// TODO: it would be nicer to retrieve this data via DDC - else the
// display is gone for good if the BIOS decides to only show the
// picture on the connected analog monitor!
gInfo->head_mode = 0;
if (read32(INTEL_DISPLAY_B_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED)
gInfo->head_mode |= HEAD_MODE_B_DIGITAL;
if (read32(INTEL_DISPLAY_A_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED)
gInfo->head_mode |= HEAD_MODE_A_ANALOG;
TRACE("pipe control for: 0x%" B_PRIx32 " 0x%" B_PRIx32 "\n",
read32(INTEL_PIPE_CONTROL), read32(INTEL_PIPE_CONTROL));
uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT);
// Probe all ports
status = probe_ports();
// If we have an enabled display pipe we save the passed information and
// assume it is the valid panel size..
// Later we query for proper EDID info if it exists, or figure something
// else out. (Default modes, etc.)
bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub();
if ((hasPCH && (lvds & PCH_LVDS_DETECTED) != 0)
|| (!hasPCH && (lvds & DISPLAY_PIPE_ENABLED) != 0)) {
save_lvds_mode();
gInfo->head_mode |= HEAD_MODE_LVDS_PANEL;
}
// On TRACE, dump ports and states
dump_ports();
TRACE("head detected: %#x\n", gInfo->head_mode);
TRACE("adpa: %08" B_PRIx32 ", dova: %08" B_PRIx32 ", dovb: %08" B_PRIx32
", lvds: %08" B_PRIx32 "\n",
read32(INTEL_DISPLAY_A_ANALOG_PORT),
read32(INTEL_DISPLAY_A_DIGITAL_PORT),
read32(INTEL_DISPLAY_B_DIGITAL_PORT),
read32(INTEL_DISPLAY_LVDS_PORT));
if (status != B_OK)
ERROR("Warning: zero active displays were found!\n");
status = assign_pipes();
if (status != B_OK)
ERROR("Warning: error while assigning pipes!\n");
status = create_mode_list();
if (status != B_OK) {
@@ -325,8 +561,22 @@ intel_get_accelerant_device_info(accelerant_device_info* info)
CALLED();
info->version = B_ACCELERANT_VERSION;
strcpy(info->name, gInfo->shared_info->device_type.InFamily(INTEL_TYPE_7xx)
? "Intel Extreme Graphics 1" : "Intel Extreme Graphics 2");
DeviceType* type = &gInfo->shared_info->device_type;
if (type->InFamily(INTEL_FAMILY_7xx))
strcpy(info->name, "Intel Extreme Graphics");
else if (type->InFamily(INTEL_FAMILY_8xx))
strcpy(info->name, "Intel Extreme Graphics 2");
else if (type->InFamily(INTEL_FAMILY_9xx))
strcpy(info->name, "Intel Graphics Media Accelerator");
else if (type->InFamily(INTEL_FAMILY_SER5))
strcpy(info->name, "Intel HD/Iris Graphics");
else if (type->InFamily(INTEL_FAMILY_POVR))
strcpy(info->name, "Intel PowerVR Graphics");
else if (type->InFamily(INTEL_FAMILY_SOC0))
strcpy(info->name, "Intel Atom Graphics");
strcpy(info->chipset, gInfo->shared_info->device_identifier);
strcpy(info->serial_no, "None");
@@ -14,6 +14,9 @@
#include <edid.h>
#include <video_overlay.h>
#include "Ports.h"
#include "Pipes.h"
struct overlay {
overlay_buffer buffer;
@@ -37,6 +40,8 @@ struct accelerant_info {
intel_shared_info* shared_info;
area_id shared_info_area;
display_mode current_mode; // pretty much a hack until per-display modes
display_mode* mode_list; // cloned list of standard display modes
area_id mode_list_area;
@@ -48,6 +53,12 @@ struct accelerant_info {
uint32 last_vertical_overlay_scale;
uint32 overlay_position_buffer_offset;
uint32 port_count;
Port* ports[MAX_PORTS];
uint32 pipe_count;
Pipe* pipes[MAX_PIPES];
edid1_info edid_info;
bool has_edid;
@@ -59,15 +70,15 @@ struct accelerant_info {
int device;
uint8 head_mode;
bool is_clone;
// LVDS panel mode passed from the bios/startup.
display_mode lvds_panel_mode;
};
#define HEAD_MODE_A_ANALOG 0x01
#define HEAD_MODE_B_DIGITAL 0x02
#define HEAD_MODE_CLONE 0x03
#define HEAD_MODE_LVDS_PANEL 0x08
#define HEAD_MODE_A_ANALOG 0x0001
#define HEAD_MODE_B_DIGITAL 0x0002
#define HEAD_MODE_CLONE 0x0003
#define HEAD_MODE_LVDS_PANEL 0x0008
#define HEAD_MODE_TESTING 0x1000
#define HEAD_MODE_STIPPI 0x2000
extern accelerant_info* gInfo;
@@ -89,6 +100,7 @@ write32(uint32 encodedRegister, uint32 value)
+ REGISTER_REGISTER(encodedRegister)) = value;
}
void dump_registers(void);
// dpms.cpp
extern void enable_display_plane(bool enable);
@@ -101,7 +113,6 @@ extern void setup_ring_buffer(ring_buffer &ringBuffer, const char* name);
// modes.cpp
extern void wait_for_vblank(void);
extern void set_frame_buffer_base(void);
extern void save_lvds_mode(void);
extern status_t create_mode_list(void);
// memory.cpp
+20 -81
View File
@@ -14,84 +14,32 @@
#undef TRACE
//#define TRACE_DPMS
#ifdef TRACE_DPMS
# define TRACE(x...) _sPrintf("intel_extreme accelerant:" x)
# define TRACE(x...) _sPrintf("intel_extreme: " x)
#else
# define TRACE(x...)
#endif
#define ERROR(x...) _sPrintf("intel_extreme accelerant: " x)
#define ERROR(x...) _sPrintf("intel_extreme: " x)
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
void
enable_display_plane(bool enable)
{
uint32 planeAControl = read32(INTEL_DISPLAY_A_CONTROL);
uint32 planeBControl = read32(INTEL_DISPLAY_B_CONTROL);
if (enable) {
// when enabling the display, the register values are updated
// automatically
if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
write32(INTEL_DISPLAY_A_CONTROL,
planeAControl | DISPLAY_CONTROL_ENABLED);
}
if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
write32(INTEL_DISPLAY_B_CONTROL,
planeBControl | DISPLAY_CONTROL_ENABLED);
}
read32(INTEL_DISPLAY_A_BASE);
// flush the eventually cached PCI bus writes
} else {
// when disabling it, we have to trigger the update using a write to
// the display base address
if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
write32(INTEL_DISPLAY_A_CONTROL,
planeAControl & ~DISPLAY_CONTROL_ENABLED);
}
if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
write32(INTEL_DISPLAY_B_CONTROL,
planeBControl & ~DISPLAY_CONTROL_ENABLED);
}
set_frame_buffer_base();
}
}
static void
enable_display_pipe(bool enable)
enable_all_pipes(bool enable)
{
uint32 pipeAControl = read32(INTEL_DISPLAY_A_PIPE_CONTROL);
uint32 pipeBControl = read32(INTEL_DISPLAY_B_PIPE_CONTROL);
// Go over each port and enable pipe/plane
for (uint32 i = 0; i < gInfo->port_count; i++) {
if (gInfo->ports[i] == NULL)
continue;
if (!gInfo->ports[i]->IsConnected())
continue;
if (enable) {
if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
write32(INTEL_DISPLAY_A_PIPE_CONTROL,
pipeAControl | DISPLAY_PIPE_ENABLED);
}
if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
write32(INTEL_DISPLAY_B_PIPE_CONTROL,
pipeBControl | DISPLAY_PIPE_ENABLED);
}
} else {
if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
write32(INTEL_DISPLAY_A_PIPE_CONTROL,
pipeAControl & ~DISPLAY_PIPE_ENABLED);
}
if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
write32(INTEL_DISPLAY_B_PIPE_CONTROL,
pipeBControl & ~DISPLAY_PIPE_ENABLED);
}
gInfo->ports[i]->Power(enable);
}
read32(INTEL_DISPLAY_A_BASE);
// flush the eventually cached PCI bus writes
// flush the possibly cached PCI bus writes
set_frame_buffer_base();
}
@@ -99,10 +47,6 @@ static void
enable_lvds_panel(bool enable)
{
bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub();
if (hasPCH) {
// TODO: fix for PCH
return;
}
int controlRegister = hasPCH ? PCH_PANEL_CONTROL : INTEL_PANEL_CONTROL;
int statusRegister = hasPCH ? PCH_PANEL_STATUS : INTEL_PANEL_STATUS;
@@ -166,8 +110,7 @@ set_display_power_mode(uint32 mode)
spin(150);
}
enable_display_pipe(true);
enable_display_plane(true);
enable_all_pipes(true);
}
wait_for_vblank();
@@ -188,25 +131,21 @@ set_display_power_mode(uint32 mode)
}
if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
write32(INTEL_DISPLAY_A_ANALOG_PORT,
(read32(INTEL_DISPLAY_A_ANALOG_PORT)
write32(INTEL_ANALOG_PORT, (read32(INTEL_ANALOG_PORT)
& ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED))
| monitorMode
| (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
}
if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
write32(INTEL_DISPLAY_B_DIGITAL_PORT,
(read32(INTEL_DISPLAY_B_DIGITAL_PORT)
& ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED))
write32(INTEL_DIGITAL_PORT_B, (read32(INTEL_DIGITAL_PORT_B)
& ~(/*DISPLAY_MONITOR_MODE_MASK |*/ DISPLAY_MONITOR_PORT_ENABLED))
| (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
// TODO: monitorMode?
}
if (mode != B_DPMS_ON) {
enable_display_plane(false);
wait_for_vblank();
enable_display_pipe(false);
}
if (mode != B_DPMS_ON)
enable_all_pipes(false);
if (mode == B_DPMS_OFF) {
write32(INTEL_DISPLAY_A_PLL, read32(INTEL_DISPLAY_A_PLL)
@@ -17,12 +17,12 @@
#undef TRACE
//#define TRACE_ENGINE
#ifdef TRACE_ENGINE
# define TRACE(x...) _sPrintf("intel_extreme accelerant:" x)
# define TRACE(x...) _sPrintf("intel_extreme: " x)
#else
# define TRACE(x...)
#endif
#define ERROR(x...) _sPrintf("intel_extreme accelerant: " x)
#define ERROR(x...) _sPrintf("intel_extreme: " x)
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
@@ -111,15 +111,15 @@ get_accelerant_hook(uint32 feature, void* data)
return (void*)intel_overlay_supported_features;
case B_ALLOCATE_OVERLAY_BUFFER:
// TODO: overlay doesn't seem to work on these chips
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_91x)
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_94x)
|| gInfo->shared_info->device_type.IsModel(INTEL_TYPE_965M)
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_G4x)
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_ILK)
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_SNB)
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IVB)
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_VLV))
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_91x)
|| gInfo->shared_info->device_type.InGroup(INTEL_GROUP_94x)
|| gInfo->shared_info->device_type.IsModel(INTEL_MODEL_965M)
|| gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)
|| gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)
|| gInfo->shared_info->device_type.InGroup(INTEL_GROUP_ILK)
|| gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_SER5)
|| gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_POVR)
|| gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_SOC0))
return NULL;
return (void*)intel_allocate_overlay_buffer;
+205 -820
View File
File diff suppressed because it is too large Load Diff
@@ -25,12 +25,12 @@
#undef TRACE
//#define TRACE_OVERLAY
#ifdef TRACE_OVERLAY
# define TRACE(x...) _sPrintf("intel_extreme accelerant:" x)
# define TRACE(x...) _sPrintf("intel_extreme: " x)
#else
# define TRACE(x...)
#endif
#define ERROR(x...) _sPrintf("intel_extreme accelerant: " x)
#define ERROR(x...) _sPrintf("intel_extreme: " x)
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
@@ -207,7 +207,7 @@ set_color_key(uint8 red, uint8 green, uint8 blue, uint8 redMask,
static void
set_color_key(const overlay_window* window)
{
switch (gInfo->shared_info->current_mode.space) {
switch (gInfo->current_mode.space) {
case B_CMAP8:
set_color_key(0, 0, window->blue.value, 0x0, 0x0, 0xff);
break;
@@ -235,7 +235,7 @@ static void
update_overlay(bool updateCoefficients)
{
if (!gInfo->shared_info->overlay_active
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_965))
|| gInfo->shared_info->device_type.IsModel(INTEL_MODEL_965))
return;
QueueCommands queue(gInfo->shared_info->primary_ring_buffer);
@@ -259,7 +259,7 @@ static void
show_overlay(void)
{
if (gInfo->shared_info->overlay_active
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_965))
|| gInfo->shared_info->device_type.IsModel(INTEL_MODEL_965))
return;
gInfo->shared_info->overlay_active = true;
@@ -281,7 +281,7 @@ static void
hide_overlay(void)
{
if (!gInfo->shared_info->overlay_active
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_965))
|| gInfo->shared_info->device_type.IsModel(INTEL_MODEL_965))
return;
overlay_registers* registers = gInfo->overlay_registers;
@@ -327,7 +327,7 @@ intel_overlay_supported_spaces(const display_mode* mode)
static const uint32 kSupportedi965Spaces[] = {B_YCbCr422, 0};
intel_shared_info &sharedInfo = *gInfo->shared_info;
if (sharedInfo.device_type.InGroup(INTEL_TYPE_96x))
if (sharedInfo.device_type.InGroup(INTEL_GROUP_96x))
return kSupportedi965Spaces;
return kSupportedSpaces;
@@ -380,7 +380,7 @@ intel_allocate_overlay_buffer(color_space colorSpace, uint16 width,
// alloc graphics mem
int32 alignment = 0x3f;
if (sharedInfo.device_type.InGroup(INTEL_TYPE_965))
if (sharedInfo.device_type.IsModel(INTEL_MODEL_965))
alignment = 0xff;
overlay_buffer* buffer = &overlay->buffer;
@@ -396,7 +396,7 @@ intel_allocate_overlay_buffer(color_space colorSpace, uint16 width,
return NULL;
}
if (sharedInfo.device_type.InGroup(INTEL_TYPE_965)) {
if (sharedInfo.device_type.IsModel(INTEL_MODEL_965)) {
status = intel_allocate_memory(INTEL_i965_OVERLAY_STATE_SIZE,
B_APERTURE_NON_RESERVED, overlay->state_base);
if (status < B_OK) {
@@ -437,7 +437,7 @@ intel_release_overlay_buffer(const overlay_buffer* buffer)
hide_overlay();
intel_free_memory(overlay->buffer_base);
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_965))
if (gInfo->shared_info->device_type.IsModel(INTEL_MODEL_965))
intel_free_memory(overlay->state_base);
free(overlay);
@@ -589,10 +589,10 @@ intel_configure_overlay(overlay_token overlayToken,
left = 0;
if (top < 0)
top = 0;
if (right > gInfo->shared_info->current_mode.timing.h_display)
right = gInfo->shared_info->current_mode.timing.h_display;
if (bottom > gInfo->shared_info->current_mode.timing.v_display)
bottom = gInfo->shared_info->current_mode.timing.v_display;
if (right > gInfo->current_mode.timing.h_display)
right = gInfo->current_mode.timing.h_display;
if (bottom > gInfo->current_mode.timing.v_display)
bottom = gInfo->current_mode.timing.v_display;
if (left >= right || top >= bottom) {
// overlay is not within visible bounds
hide_overlay();
@@ -630,7 +630,7 @@ intel_configure_overlay(overlay_token overlayToken,
// the result will be wrong, too.
registers->source_width_rgb = right - left;
registers->source_height_rgb = bottom - top;
if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_8xx)) {
if (gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_8xx)) {
registers->source_bytes_per_row_rgb = (((overlay->buffer_offset
+ (view->width << 1) + 0x1f) >> 5)
- (overlay->buffer_offset >> 5) - 1) << 2;
@@ -0,0 +1,279 @@
/*
* Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Alexander von Gluck IV, kallisti5@unixzen.com
*/
#include "pll.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <Debug.h>
#include <create_display_modes.h>
#include <ddc.h>
#include <edid.h>
#include <validate_display_mode.h>
#include "accelerant_protos.h"
#include "accelerant.h"
#include "utility.h"
#undef TRACE
#define TRACE_MODE
#ifdef TRACE_MODE
# define TRACE(x...) _sPrintf("intel_extreme: " x)
#else
# define TRACE(x...)
#endif
#define ERROR(x...) _sPrintf("intel_extreme: " x)
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
void
get_pll_limits(pll_limits* limits, bool isLVDS)
{
// Note, the limits are taken from the X driver; they have not yet been
// tested
// TODO: Breakout BXT
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) {
pll_limits kLimits = {
// p, p1, p2, high, n, m, m1, m2
{ 5, 2, 14, false, 1, 79, 2, 24 << 22}, // min
{ 80, 4, 1, true, 1, 127, 2, 175 << 22}, // max
225000, 4800000, 6480000
};
memcpy(limits, &kLimits, sizeof(pll_limits));
} else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) {
pll_limits kLimits = {
// p, p1, p2, high, n, m, m1, m2
{ 5, 2, 20, false, 1, 79, 2, 11}, // min
{ 80, 3, 2, true, 7, 127, 3, 156}, // max
225000, 4000000, 6000000
};
memcpy(limits, &kLimits, sizeof(pll_limits));
} else if (gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_SER5)
|| gInfo->shared_info->device_type.InGroup(INTEL_GROUP_BXT)) {
pll_limits kLimits = {
// p, p1, p2, high, n, m, m1, m2
{ 5, 1, 10, false, 1, 79, 12, 5}, // min
{ 80, 8, 5, true, 5, 127, 22, 9}, // max
225000, 1760000, 3510000
};
// TODO: validate these LVDS dividers!
if (isLVDS) {
kLimits.min.post = 7;
kLimits.max.post = 98;
kLimits.min.post2 = 14;
kLimits.max.post2 = 7;
}
memcpy(limits, &kLimits, sizeof(pll_limits));
} else if (gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_9xx)) {
pll_limits kLimits = {
// p, p1, p2, high, n, m, m1, m2
{ 5, 1, 10, false, 1, 70, 8, 3}, // min
{ 80, 8, 5, true, 6, 120, 18, 7}, // max
200000, 1400000, 2800000
};
if (isLVDS) {
kLimits.min.post = 7;
kLimits.max.post = 98;
kLimits.min.post2 = 14;
kLimits.max.post2 = 7;
}
memcpy(limits, &kLimits, sizeof(pll_limits));
} else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)) {
pll_limits kLimits = {
// p, p1, p2, high, n, m, m1, m2
{ 10, 1, 10, false, 1, 104, 17, 5}, // min
{ 30, 3, 10, true, 4, 138, 23, 11}, // max
270000, 1750000, 3500000
};
// TODO: validate these LVDS dividers!
if (isLVDS) {
kLimits.min.post = 7;
kLimits.max.post = 98;
kLimits.min.post2 = 14;
kLimits.max.post2 = 7;
}
memcpy(limits, &kLimits, sizeof(pll_limits));
} else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) {
// m1 is reserved and must be 0
pll_limits kLimits = {
// p, p1, p2, high, n, m, m1, m2
{ 5, 1, 10, false, 3, 2, 0, 2}, // min
{ 80, 8, 5, true, 6, 256, 0, 254}, // max
200000, 1700000, 3500000
};
if (isLVDS) {
kLimits.min.post = 7;
kLimits.max.post = 112;
kLimits.min.post2 = 14;
kLimits.max.post2 = 14;
}
memcpy(limits, &kLimits, sizeof(pll_limits));
} else {
static pll_limits kLimits = {
// p, p1, p2, high, n, m, m1, m2
{ 4, 2, 4, false, 5, 96, 20, 8},
{128, 33, 2, true, 18, 140, 28, 18},
165000, 930000, 1400000
};
// TODO: Validate these LVDS dividers!
if (isLVDS) {
kLimits.min.post = 7;
kLimits.max.post = 98;
kLimits.min.post2 = 14;
kLimits.max.post2 = 7;
}
memcpy(limits, &kLimits, sizeof(pll_limits));
}
TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", "
"p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
"(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits->min.post,
limits->min.post1, limits->min.post2, limits->min.n, limits->min.m,
limits->min.m1, limits->min.m2);
TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", "
"p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " "
"(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits->max.post,
limits->max.post1, limits->max.post2, limits->max.n, limits->max.m,
limits->max.m1, limits->max.m2);
}
bool
valid_pll_divisors(pll_divisors* divisors, pll_limits* limits)
{
pll_info &info = gInfo->shared_info->pll_info;
uint32 vco = info.reference_frequency * divisors->m / divisors->n;
uint32 frequency = vco / divisors->post;
if (divisors->post < limits->min.post || divisors->post > limits->max.post
|| divisors->m < limits->min.m || divisors->m > limits->max.m
|| vco < limits->min_vco || vco > limits->max_vco
|| frequency < info.min_frequency || frequency > info.max_frequency)
return false;
return true;
}
static uint32
compute_pll_m(pll_divisors* divisors)
{
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)
|| gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) {
return divisors->m1 * divisors->m2;
}
// Pineview, m1 is reserved
if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN))
return divisors->m2 + 2;
if (gInfo->shared_info->device_type.Generation() >= 3)
return 5 * (divisors->m1 + 2) + (divisors->m2 + 2);
// TODO: This logic needs validated... PLL's were calculated differently
// on 8xx chipsets
return 5 * divisors->m1 + divisors->m2;
}
static uint32
compute_pll_p(pll_divisors* divisors)
{
return divisors->post1 * divisors->post2;
}
void
compute_pll_divisors(display_mode* current, pll_divisors* divisors,
bool isLVDS)
{
float requestedPixelClock = current->timing.pixel_clock / 1000.0f;
float referenceClock
= gInfo->shared_info->pll_info.reference_frequency / 1000.0f;
pll_limits limits;
get_pll_limits(&limits, isLVDS);
TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock);
// Calculate p2
if (isLVDS) {
if (requestedPixelClock > 112.999
|| (read32(INTEL_DIGITAL_LVDS_PORT) & LVDS_CLKB_POWER_MASK)
== LVDS_CLKB_POWER_UP) {
// fast DAC timing via 2 channels
divisors->post2 = limits.max.post2;
divisors->post2_high = limits.max.post2_high;
} else {
// slow DAC timing
divisors->post2 = limits.min.post2;
divisors->post2_high = limits.min.post2_high;
}
} else {
if (current->timing.pixel_clock < limits.min_post2_frequency) {
// slow DAC timing
divisors->post2 = limits.min.post2;
divisors->post2_high = limits.min.post2_high;
} else {
// fast DAC timing
divisors->post2 = limits.max.post2;
divisors->post2_high = limits.max.post2_high;
}
}
float best = requestedPixelClock;
pll_divisors bestDivisors;
bool is_pine = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN);
for (divisors->m1 = limits.min.m1; divisors->m1 <= limits.max.m1;
divisors->m1++) {
for (divisors->m2 = limits.min.m2; divisors->m2 <= limits.max.m2
&& ((divisors->m2 < divisors->m1) || is_pine); divisors->m2++) {
for (divisors->n = limits.min.n; divisors->n <= limits.max.n;
divisors->n++) {
for (divisors->post1 = limits.min.post1;
divisors->post1 <= limits.max.post1; divisors->post1++) {
divisors->m = compute_pll_m(divisors);
divisors->post = compute_pll_p(divisors);
if (!valid_pll_divisors(divisors, &limits))
continue;
float error = fabs(requestedPixelClock
- ((referenceClock * divisors->m) / divisors->n)
/ divisors->post);
if (error < best) {
best = error;
bestDivisors = *divisors;
if (error == 0)
break;
}
}
}
}
}
*divisors = bestDivisors;
TRACE("%s: found: %g MHz, p = %" B_PRId32 " (p1 = %" B_PRId32 ", "
"p2 = %" B_PRId32 "), n = %" B_PRId32 ", m = %" B_PRId32 " "
"(m1 = %" B_PRId32 ", m2 = %" B_PRId32 ")\n", __func__,
((referenceClock * divisors->m) / divisors->n) / divisors->post,
divisors->post, divisors->post1, divisors->post2, divisors->n,
divisors->m, divisors->m1, divisors->m2);
}
@@ -0,0 +1,42 @@
/*
* Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Alexander von Gluck IV, kallisti5@unixzen.com
*/
#ifndef INTEL_EXTREME_PLL_H
#define INTEL_EXTREME_PLL_H
#include "intel_extreme.h"
struct pll_divisors {
uint32 post;
uint32 post1;
uint32 post2;
bool post2_high;
uint32 n;
uint32 m;
uint32 m1;
uint32 m2;
};
struct pll_limits {
pll_divisors min;
pll_divisors max;
uint32 min_post2_frequency;
uint32 min_vco;
uint32 max_vco;
};
void get_pll_limits(pll_limits* limits, bool isLVDS);
bool valid_pll_divisors(pll_divisors* divisors, pll_limits* limits);
void compute_pll_divisors(display_mode* current, pll_divisors* divisors,
bool isLVDS);
#endif /* INTEL_EXTREME_PLL_H */
+207 -176
View File
@@ -21,13 +21,16 @@
#include <KernelExport.h>
#include <PCI.h>
#include <new>
//#define TRACE_INTEL
#define TRACE_INTEL
#ifdef TRACE_INTEL
# define TRACE(x...) dprintf("\33[33magp-intel:\33[0m " x)
# define TRACE(x...) dprintf("intel_gart: " x)
#else
# define TRACE(x...) ;
#endif
#define ERROR(x...) dprintf("intel_gart: " x)
#ifndef __HAIKU__
# define B_KERNEL_READ_AREA 0
@@ -47,93 +50,95 @@
(*((volatile uint32*)(address)))
// PCI "Host bridge" is most cases :-)
const struct supported_device {
uint32 bridge_id;
uint32 display_id;
uint32 type;
int32 type;
const char *name;
} kSupportedDevices[] = {
{0x3575, 0x3577, INTEL_TYPE_83x, "i830GM"},
{0x2560, 0x2562, INTEL_TYPE_83x, "i845G"},
{0x3580, 0x3582, INTEL_TYPE_85x, "i855G"},
{0x358c, 0x358e, INTEL_TYPE_85x, "i855G"},
{0x2570, 0x2572, INTEL_TYPE_85x, "i865G"},
{0x3575, 0x3577, INTEL_GROUP_83x, "i830GM"},
{0x2560, 0x2562, INTEL_GROUP_83x, "i845G"},
{0x3580, 0x3582, INTEL_GROUP_85x, "i855G"},
{0x358c, 0x358e, INTEL_GROUP_85x, "i855G"},
{0x2570, 0x2572, INTEL_GROUP_85x, "i865G"},
// {0x2792, INTEL_TYPE_91x, "i910"},
// {0x258a, INTEL_TYPE_91x, "i915"},
{0x2580, 0x2582, INTEL_TYPE_915, "i915G"},
{0x2590, 0x2592, INTEL_TYPE_915M, "i915GM"},
{0x2770, 0x2772, INTEL_TYPE_945, "i945G"},
{0x27a0, 0x27a2, INTEL_TYPE_945M, "i945GM"},
{0x27ac, 0x27ae, INTEL_TYPE_945M, "i945GME"},
// {0x2792, INTEL_GROUP_91x, "i910"},
// {0x258a, INTEL_GROUP_91x, "i915"},
{0x2580, 0x2582, INTEL_MODEL_915, "i915G"},
{0x2590, 0x2592, INTEL_MODEL_915M, "i915GM"},
{0x2770, 0x2772, INTEL_MODEL_945, "i945G"},
{0x27a0, 0x27a2, INTEL_MODEL_945M, "i945GM"},
{0x27ac, 0x27ae, INTEL_MODEL_945M, "i945GME"},
{0x2970, 0x2972, INTEL_TYPE_965, "i946GZ"},
{0x2980, 0x2982, INTEL_TYPE_965, "G35"},
{0x2990, 0x2992, INTEL_TYPE_965, "i965Q"},
{0x29a0, 0x29a2, INTEL_TYPE_965, "i965G"},
{0x2a00, 0x2a02, INTEL_TYPE_965, "i965GM"},
{0x2a10, 0x2a12, INTEL_TYPE_965, "i965GME"},
{0x2970, 0x2972, INTEL_MODEL_965, "i946GZ"},
{0x2980, 0x2982, INTEL_MODEL_965, "G35"},
{0x2990, 0x2992, INTEL_MODEL_965, "i965Q"},
{0x29a0, 0x29a2, INTEL_MODEL_965, "i965G"},
{0x2a00, 0x2a02, INTEL_MODEL_965, "i965GM"},
{0x2a10, 0x2a12, INTEL_MODEL_965, "i965GME"},
{0x29b0, 0x29b2, INTEL_TYPE_G33, "G33"},
{0x29c0, 0x29c2, INTEL_TYPE_G33, "Q35"},
{0x29d0, 0x29d2, INTEL_TYPE_G33, "Q33"},
{0x29b0, 0x29b2, INTEL_MODEL_G33, "G33"},
{0x29c0, 0x29c2, INTEL_MODEL_G33, "Q35"},
{0x29d0, 0x29d2, INTEL_MODEL_G33, "Q33"},
{0x2a40, 0x2a42, INTEL_TYPE_GM45, "GM45"},
{0x2e00, 0x2e02, INTEL_TYPE_G45, "IGD"},
{0x2e10, 0x2e12, INTEL_TYPE_G45, "Q45"},
{0x2e20, 0x2e22, INTEL_TYPE_G45, "G45"},
{0x2e30, 0x2e32, INTEL_TYPE_G45, "G41"},
{0x2e40, 0x2e42, INTEL_TYPE_G45, "B43"},
{0x2e90, 0x2e92, INTEL_TYPE_G45, "B43"},
{0x2a40, 0x2a42, INTEL_MODEL_GM45, "GM45"},
{0x2e00, 0x2e02, INTEL_MODEL_G45, "IGD"},
{0x2e10, 0x2e12, INTEL_MODEL_G45, "Q45"},
{0x2e20, 0x2e22, INTEL_MODEL_G45, "G45"},
{0x2e30, 0x2e32, INTEL_MODEL_G45, "G41"},
{0x2e40, 0x2e42, INTEL_MODEL_G45, "B43"},
{0x2e90, 0x2e92, INTEL_MODEL_G45, "B43"},
{0xa000, 0xa001, INTEL_TYPE_IGDG, "Atom_Dx10"},
{0xa010, 0xa011, INTEL_TYPE_IGDGM, "Atom_N4x0"},
{0xa000, 0xa001, INTEL_MODEL_PINE, "Atom_Dx10"},
{0xa010, 0xa011, INTEL_MODEL_PINEM, "Atom_N4x0"},
{0x0040, 0x0042, INTEL_TYPE_ILKG, "IronLake Desktop"},
{0x0044, 0x0046, INTEL_TYPE_ILKGM, "IronLake Mobile"},
{0x0062, 0x0046, INTEL_TYPE_ILKGM, "IronLake Mobile"},
{0x006a, 0x0046, INTEL_TYPE_ILKGM, "IronLake Mobile"},
{0x0040, 0x0042, INTEL_MODEL_ILKG, "IronLake Desktop"},
{0x0044, 0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"},
{0x0062, 0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"},
{0x006a, 0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"},
{0x0100, 0x0102, INTEL_TYPE_SNBG, "SandyBridge Desktop GT1"},
{0x0100, 0x0112, INTEL_TYPE_SNBG, "SandyBridge Desktop GT2"},
{0x0100, 0x0122, INTEL_TYPE_SNBG, "SandyBridge Desktop GT2+"},
{0x0104, 0x0106, INTEL_TYPE_SNBGM, "SandyBridge Mobile GT1"},
{0x0104, 0x0116, INTEL_TYPE_SNBGM, "SandyBridge Mobile GT2"},
{0x0104, 0x0126, INTEL_TYPE_SNBGM, "SandyBridge Mobile GT2+"},
{0x0108, 0x010a, INTEL_TYPE_SNBGS, "SandyBridge Server"},
{0x0100, 0x0102, INTEL_MODEL_SNBG, "SandyBridge Desktop GT1"},
{0x0100, 0x0112, INTEL_MODEL_SNBG, "SandyBridge Desktop GT2"},
{0x0100, 0x0122, INTEL_MODEL_SNBG, "SandyBridge Desktop GT2+"},
{0x0104, 0x0106, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT1"},
{0x0104, 0x0116, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT2"},
{0x0104, 0x0126, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT2+"},
{0x0108, 0x010a, INTEL_MODEL_SNBGS, "SandyBridge Server"},
{0x0150, 0x0152, INTEL_TYPE_IVBG, "IvyBridge Desktop GT1"},
{0x0150, 0x0162, INTEL_TYPE_IVBG, "IvyBridge Desktop GT2"},
{0x0154, 0x0156, INTEL_TYPE_IVBGM, "IvyBridge Mobile GT1"},
{0x0154, 0x0166, INTEL_TYPE_IVBGM, "IvyBridge Mobile GT2"},
{0x0158, 0x015a, INTEL_TYPE_IVBGS, "IvyBridge Server GT1"},
{0x0158, 0x016a, INTEL_TYPE_IVBGS, "IvyBridge Server GT2"},
{0x0150, 0x0152, INTEL_MODEL_IVBG, "IvyBridge Desktop GT1"},
{0x0150, 0x0162, INTEL_MODEL_IVBG, "IvyBridge Desktop GT2"},
{0x0154, 0x0156, INTEL_MODEL_IVBGM, "IvyBridge Mobile GT1"},
{0x0154, 0x0166, INTEL_MODEL_IVBGM, "IvyBridge Mobile GT2"},
{0x0158, 0x015a, INTEL_MODEL_IVBGS, "IvyBridge Server GT1"},
{0x0158, 0x016a, INTEL_MODEL_IVBGS, "IvyBridge Server GT2"},
{0x0c00, 0x0412, INTEL_TYPE_IVBG, "Haswell Desktop"},
{0x0c04, 0x0416, INTEL_TYPE_IVBGM, "Haswell Mobile"},
{0x0d04, 0x0d26, INTEL_TYPE_IVBGM, "Haswell Mobile"},
{0x0c00, 0x0412, INTEL_MODEL_HAS, "Haswell Desktop"},
{0x0c04, 0x0416, INTEL_MODEL_HASM, "Haswell Mobile"},
{0x0d04, 0x0d26, INTEL_MODEL_HASM, "Haswell Mobile"},
{0x0a04, 0x0a16, INTEL_MODEL_HASM, "Haswell Mobile"},
// XXX: 0x0f00 only confirmed on 0x0f30, 0x0f31
{0x0f00, 0x0155, INTEL_TYPE_VLVG, "ValleyView Desktop"},
{0x0f00, 0x0f30, INTEL_TYPE_VLVGM, "ValleyView Mobile"},
{0x0f00, 0x0f31, INTEL_TYPE_VLVGM, "ValleyView Mobile"},
{0x0f00, 0x0f32, INTEL_TYPE_VLVGM, "ValleyView Mobile"},
{0x0f00, 0x0f33, INTEL_TYPE_VLVGM, "ValleyView Mobile"},
{0x0f00, 0x0157, INTEL_TYPE_VLVGM, "ValleyView Mobile"},
{0x0f00, 0x0155, INTEL_MODEL_VLV, "ValleyView Desktop"},
{0x0f00, 0x0f30, INTEL_MODEL_VLVM, "ValleyView Mobile"},
{0x0f00, 0x0f31, INTEL_MODEL_VLVM, "ValleyView Mobile"},
{0x0f00, 0x0f32, INTEL_MODEL_VLVM, "ValleyView Mobile"},
{0x0f00, 0x0f33, INTEL_MODEL_VLVM, "ValleyView Mobile"},
{0x0f00, 0x0157, INTEL_MODEL_VLVM, "ValleyView Mobile"},
};
struct intel_info {
pci_info bridge;
pci_info display;
uint32 type;
DeviceType* type;
uint32 *gtt_base;
uint32* gtt_base;
phys_addr_t gtt_physical_base;
area_id gtt_area;
size_t gtt_entries;
size_t gtt_stolen_entries;
vuint32 *registers;
vuint32* registers;
area_id registers_area;
addr_t aperture_base;
@@ -167,99 +172,29 @@ has_display_device(pci_info &info, uint32 deviceID)
}
static void
determine_memory_sizes(intel_info &info, size_t &gttSize, size_t &stolenSize)
static uint16
gtt_memory_config(intel_info &info)
{
// read stolen memory from the PCI configuration of the PCI bridge
uint8 controlRegister = INTEL_GRAPHICS_MEMORY_CONTROL;
if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB)
if (info.type->InGroup(INTEL_GROUP_SNB))
controlRegister = SNB_GRAPHICS_MEMORY_CONTROL;
uint16 memoryConfig = get_pci_config(info.bridge, controlRegister, 2);
return get_pci_config(info.bridge, controlRegister, 2);
}
static size_t
determine_gtt_stolen(intel_info &info)
{
uint16 memoryConfig = gtt_memory_config(info);
size_t memorySize = 1 << 20; // 1 MB
gttSize = 0;
stolenSize = 0;
if (info.type == INTEL_TYPE_965) {
switch (memoryConfig & i965_GTT_MASK) {
case i965_GTT_128K:
gttSize = 128 << 10;
break;
case i965_GTT_256K:
gttSize = 256 << 10;
break;
case i965_GTT_512K:
gttSize = 512 << 10;
break;
}
} else if (info.type == INTEL_TYPE_G33
|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_IGD) {
switch (memoryConfig & G33_GTT_MASK) {
case G33_GTT_1M:
gttSize = 1 << 20;
break;
case G33_GTT_2M:
gttSize = 2 << 20;
break;
}
} else if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x
|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_ILK) {
switch (memoryConfig & G4X_GTT_MASK) {
case G4X_GTT_NONE:
gttSize = 0;
break;
case G4X_GTT_1M_NO_IVT:
gttSize = 1 << 20;
break;
case G4X_GTT_2M_NO_IVT:
case G4X_GTT_2M_IVT:
gttSize = 2 << 20;
break;
case G4X_GTT_3M_IVT:
gttSize = 3 << 20;
break;
case G4X_GTT_4M_IVT:
gttSize = 4 << 20;
break;
}
} else if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB) {
switch (memoryConfig & SNB_GTT_SIZE_MASK) {
case SNB_GTT_SIZE_NONE:
gttSize = 0;
break;
case SNB_GTT_SIZE_1MB:
gttSize = 1 << 20;
break;
case SNB_GTT_SIZE_2MB:
gttSize = 2 << 20;
break;
}
} else {
// older models have the GTT as large as their frame buffer mapping
// TODO: check if the i9xx version works with the i8xx chips as well
size_t frameBufferSize = 0;
if ((info.type & INTEL_TYPE_8xx) != 0) {
if (info.type == INTEL_TYPE_83x
&& (memoryConfig & MEMORY_MASK) == i830_FRAME_BUFFER_64M)
frameBufferSize = 64 << 20;
else
frameBufferSize = 128 << 20;
} else if ((info.type & INTEL_TYPE_9xx) != 0)
frameBufferSize = info.display.u.h0.base_register_sizes[2];
TRACE("frame buffer size %lu MB\n", frameBufferSize >> 20);
gttSize = frameBufferSize / 1024;
}
// TODO: test with different models!
if (info.type == INTEL_TYPE_83x) {
if (info.type->InGroup(INTEL_GROUP_83x)) {
// Older chips
switch (memoryConfig & STOLEN_MEMORY_MASK) {
case i830_LOCAL_MEMORY_ONLY:
// TODO: determine its size!
dprintf("intel_gart: getting local memory size not "
"implemented.\n");
ERROR("getting local memory size not implemented.\n");
break;
case i830_STOLEN_512K:
memorySize >>= 1;
@@ -271,7 +206,7 @@ determine_memory_sizes(intel_info &info, size_t &gttSize, size_t &stolenSize)
memorySize *= 8;
break;
}
} else if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB) {
} else if (info.type->InGroup(INTEL_GROUP_SNB)) {
switch (memoryConfig & SNB_STOLEN_MEMORY_MASK) {
case SNB_STOLEN_MEMORY_32MB:
memorySize *= 32;
@@ -322,8 +257,11 @@ determine_memory_sizes(intel_info &info, size_t &gttSize, size_t &stolenSize)
memorySize *= 512;
break;
}
} else if (info.type == INTEL_TYPE_85x
|| (info.type & INTEL_TYPE_9xx) == INTEL_TYPE_9xx) {
} else if (info.type->InGroup(INTEL_GROUP_85x)
|| info.type->InFamily(INTEL_FAMILY_9xx)
|| info.type->InFamily(INTEL_FAMILY_SER5)
|| info.type->InFamily(INTEL_FAMILY_SOC0)
|| info.type->InFamily(INTEL_FAMILY_POVR)) {
switch (memoryConfig & STOLEN_MEMORY_MASK) {
case i855_STOLEN_MEMORY_4M:
memorySize *= 4;
@@ -366,14 +304,109 @@ determine_memory_sizes(intel_info &info, size_t &gttSize, size_t &stolenSize)
// TODO: error out!
memorySize = 4096;
}
return memorySize - 4096;
}
stolenSize = memorySize - 4096;
static size_t
determine_gtt_size(intel_info &info)
{
uint16 memoryConfig = gtt_memory_config(info);
size_t gttSize = 0;
if (info.type->IsModel(INTEL_MODEL_965)) {
switch (memoryConfig & i965_GTT_MASK) {
case i965_GTT_128K:
gttSize = 128 << 10;
break;
case i965_GTT_256K:
gttSize = 256 << 10;
break;
case i965_GTT_512K:
gttSize = 512 << 10;
break;
}
} else if (info.type->IsModel(INTEL_MODEL_G33)
|| info.type->InGroup(INTEL_GROUP_PIN)) {
switch (memoryConfig & G33_GTT_MASK) {
case G33_GTT_1M:
gttSize = 1 << 20;
break;
case G33_GTT_2M:
gttSize = 2 << 20;
break;
}
} else if (info.type->InGroup(INTEL_GROUP_G4x)
|| info.type->InGroup(INTEL_GROUP_ILK)) {
switch (memoryConfig & G4X_GTT_MASK) {
case G4X_GTT_NONE:
gttSize = 0;
break;
case G4X_GTT_1M_NO_IVT:
gttSize = 1 << 20;
break;
case G4X_GTT_2M_NO_IVT:
case G4X_GTT_2M_IVT:
gttSize = 2 << 20;
break;
case G4X_GTT_3M_IVT:
gttSize = 3 << 20;
break;
case G4X_GTT_4M_IVT:
gttSize = 4 << 20;
break;
}
} else if (info.type->InGroup(INTEL_GROUP_SNB)) {
switch (memoryConfig & SNB_GTT_SIZE_MASK) {
case SNB_GTT_SIZE_NONE:
gttSize = 0;
break;
case SNB_GTT_SIZE_1MB:
gttSize = 1 << 20;
break;
case SNB_GTT_SIZE_2MB:
gttSize = 2 << 20;
break;
}
} else {
// older models have the GTT as large as their frame buffer mapping
// TODO: check if the i9xx version works with the i8xx chips as well
size_t frameBufferSize = 0;
if (info.type->InFamily(INTEL_FAMILY_8xx)) {
if (info.type->InGroup(INTEL_GROUP_83x)
&& (memoryConfig & MEMORY_MASK) == i830_FRAME_BUFFER_64M)
frameBufferSize = 64 << 20;
else
frameBufferSize = 128 << 20;
} else if (info.type->Generation() >= 3) {
frameBufferSize = info.display.u.h0.base_register_sizes[2];
}
TRACE("frame buffer size %lu MB\n", frameBufferSize >> 20);
gttSize = frameBufferSize / 1024;
}
return gttSize;
}
static void
set_gtt_entry(intel_info &info, uint32 offset, phys_addr_t physicalAddress)
{
if (info.type->Generation() >= 8) {
// CHV + BXT
physicalAddress |= (physicalAddress >> 28) & 0x07f0;
// TODO: cache control?
} else if (info.type->Generation() >= 6) {
// SandyBridge, IronLake, IvyBridge, Haswell
physicalAddress |= (physicalAddress >> 28) & 0x0ff0;
physicalAddress |= 0x02; // cache control, l3 cacheable
} else if (info.type->Generation() >= 4) {
// Intel 9xx minus 91x, 94x, G33
// possible high bits are stored in the lower end
physicalAddress |= (physicalAddress >> 28) & 0x00f0;
// TODO: cache control?
}
// TODO: this is not 64-bit safe!
write32(info.gtt_base + (offset >> GTT_PAGE_SHIFT),
(uint32)physicalAddress | GTT_ENTRY_VALID);
@@ -396,7 +429,7 @@ intel_map(intel_info &info)
{
int fbIndex = 0;
int mmioIndex = 1;
if ((info.type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_9xx) {
if (info.type->Generation() >= 3) {
// for some reason Intel saw the need to change the order of the
// mappings with the introduction of the i9xx family
mmioIndex = 0;
@@ -410,7 +443,7 @@ intel_map(intel_info &info)
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.registers);
if (mmioMapper.InitCheck() < B_OK) {
dprintf("agp_intel: could not map memory I/O!\n");
ERROR("could not map memory I/O!\n");
return info.registers_area;
}
@@ -425,7 +458,7 @@ intel_map(intel_info &info)
&scratchAddress, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
if (scratchCreator.InitCheck() < B_OK) {
dprintf("agp_intel: could not create scratch page!\n");
ERROR("could not create scratch page!\n");
return info.scratch_area;
}
@@ -433,29 +466,27 @@ intel_map(intel_info &info)
if (get_memory_map(scratchAddress, B_PAGE_SIZE, &entry, 1) != B_OK)
return B_ERROR;
if ((info.type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_9xx) {
if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x
|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_ILK
|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB) {
info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
+ (2UL << 20);
} else
info.gtt_physical_base
= get_pci_config(info.display, i915_GTT_BASE, 4);
} else {
// TODO: Review these
if (info.type->InFamily(INTEL_FAMILY_8xx)) {
info.gtt_physical_base = read32(info.registers
+ INTEL_PAGE_TABLE_CONTROL) & ~PAGE_TABLE_ENABLED;
if (info.gtt_physical_base == 0) {
// TODO: not sure how this is supposed to work under Linux/FreeBSD,
// but on my i865, this code is needed for Haiku.
dprintf("intel_gart: Use GTT address fallback.\n");
ERROR("Use GTT address fallback.\n");
info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
+ i830_GTT_BASE;
}
} else if (info.type->InGroup(INTEL_GROUP_91x)) {
info.gtt_physical_base = get_pci_config(info.display, i915_GTT_BASE, 4);
} else {
// 945+?
info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
+ (2UL << 20);
}
size_t gttSize, stolenSize;
determine_memory_sizes(info, gttSize, stolenSize);
size_t gttSize = determine_gtt_size(info);
size_t stolenSize = determine_gtt_stolen(info);
info.gtt_entries = gttSize / 4096;
info.gtt_stolen_entries = stolenSize / 4096;
@@ -468,7 +499,7 @@ intel_map(intel_info &info)
info.gtt_physical_base, gttSize, B_ANY_KERNEL_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.gtt_base);
if (gttMapper.InitCheck() < B_OK) {
dprintf("intel_gart: could not map GTT!\n");
ERROR("could not map GTT!\n");
return info.gtt_area;
}
@@ -477,16 +508,14 @@ intel_map(intel_info &info)
if (info.aperture_size == 0)
info.aperture_size = info.display.u.h0.base_register_sizes[fbIndex];
dprintf("intel_gart: detected %ld MB of stolen memory, aperture "
"size %ld MB, GTT size %ld KB\n", (stolenSize + (1023 << 10)) >> 20,
ERROR("detected %ld MB of stolen memory, aperture size %ld MB, "
"GTT size %ld KB\n", (stolenSize + (1023 << 10)) >> 20,
info.aperture_size >> 20, gttSize >> 10);
dprintf("intel_gart: GTT base = 0x%" B_PRIxPHYSADDR "\n",
info.gtt_physical_base);
dprintf("intel_gart: MMIO base = 0x%" B_PRIx32 "\n",
ERROR("GTT base = 0x%" B_PRIxPHYSADDR "\n", info.gtt_physical_base);
ERROR("MMIO base = 0x%" B_PRIx32 "\n",
info.display.u.h0.base_registers[mmioIndex]);
dprintf("intel_gart: GMR base = 0x%" B_PRIxPHYSADDR "\n",
info.aperture_physical_base);
ERROR("GMR base = 0x%" B_PRIxPHYSADDR "\n", info.aperture_physical_base);
AreaKeeper apertureMapper;
info.aperture_area = apertureMapper.Map("intel graphics aperture",
@@ -495,7 +524,7 @@ intel_map(intel_info &info)
B_READ_AREA | B_WRITE_AREA, (void**)&info.aperture_base);
if (apertureMapper.InitCheck() < B_OK) {
// try again without write combining
dprintf(DEVICE_NAME ": enabling write combined mode failed.\n");
ERROR("enabling write combined mode failed.\n");
info.aperture_area = apertureMapper.Map("intel graphics aperture",
info.aperture_physical_base, info.aperture_size,
@@ -503,7 +532,7 @@ intel_map(intel_info &info)
(void**)&info.aperture_base);
}
if (apertureMapper.InitCheck() < B_OK) {
dprintf(DEVICE_NAME ": could not map graphics aperture!\n");
ERROR("could not map graphics aperture!\n");
return info.aperture_area;
}
@@ -639,7 +668,7 @@ intel_init()
for (uint32 i = 0; i < sizeof(kSupportedDevices)
/ sizeof(kSupportedDevices[0]); i++) {
if (sInfo.bridge.device_id == kSupportedDevices[i].bridge_id) {
sInfo.type = kSupportedDevices[i].type;
sInfo.type = new DeviceType(kSupportedDevices[i].type);
if (has_display_device(sInfo.display,
kSupportedDevices[i].display_id)) {
TRACE("found intel bridge\n");
@@ -656,6 +685,8 @@ intel_init()
static void
intel_uninit()
{
if (sInfo.type)
delete sInfo.type;
}
@@ -119,8 +119,6 @@ static struct vbios {
} vbios;
/* TODO: move code to accelerant, if possible */
/*! This is reimplementation, Haiku uses BIOS call and gets most current panel
info, we're, otherwise, digging in VBIOS memory and parsing VBT tables to
get native panel timings. This will allow to get non-updated,
@@ -42,71 +42,75 @@ const struct supported_device {
int32 type;
const char* name;
} kSupportedDevices[] = {
{0x3577, INTEL_TYPE_83x, "i830GM"},
{0x2562, INTEL_TYPE_83x, "i845G"},
{0x3577, INTEL_GROUP_83x, "i830GM"},
{0x2562, INTEL_GROUP_83x, "i845G"},
{0x2572, INTEL_TYPE_85x, "i865G"},
{0x3582, INTEL_TYPE_85x, "i855G"},
{0x358e, INTEL_TYPE_85x, "i855G"},
{0x2572, INTEL_GROUP_85x, "i865G"},
{0x3582, INTEL_GROUP_85x, "i855G"},
{0x358e, INTEL_GROUP_85x, "i855G"},
{0x2582, INTEL_TYPE_915, "i915G"},
{0x258a, INTEL_TYPE_915, "i915"},
{0x2592, INTEL_TYPE_915M, "i915GM"},
{0x2792, INTEL_TYPE_915, "i910"},
{0x2772, INTEL_TYPE_945, "i945G"},
{0x27a2, INTEL_TYPE_945M, "i945GM"},
{0x27ae, INTEL_TYPE_945M, "i945GME"},
{0x2972, INTEL_TYPE_965, "i946G"},
{0x2982, INTEL_TYPE_965, "G35"},
{0x2992, INTEL_TYPE_965, "i965Q"},
{0x29a2, INTEL_TYPE_965, "i965G"},
{0x2a02, INTEL_TYPE_965M, "i965GM"},
{0x2a12, INTEL_TYPE_965M, "i965GME"},
{0x29b2, INTEL_TYPE_G33, "G33G"},
{0x29c2, INTEL_TYPE_G33, "Q35G"},
{0x29d2, INTEL_TYPE_G33, "Q33G"},
{0x2582, INTEL_MODEL_915, "i915G"},
{0x258a, INTEL_MODEL_915, "i915"},
{0x2592, INTEL_MODEL_915M, "i915GM"},
{0x2792, INTEL_MODEL_915, "i910"},
{0x2772, INTEL_MODEL_945, "i945G"},
{0x27a2, INTEL_MODEL_945M, "i945GM"},
{0x27ae, INTEL_MODEL_945M, "i945GME"},
{0x2972, INTEL_MODEL_965, "i946G"},
{0x2982, INTEL_MODEL_965, "G35"},
{0x2992, INTEL_MODEL_965, "i965Q"},
{0x29a2, INTEL_MODEL_965, "i965G"},
{0x2a02, INTEL_MODEL_965M, "i965GM"},
{0x2a12, INTEL_MODEL_965M, "i965GME"},
{0x29b2, INTEL_MODEL_G33, "G33G"},
{0x29c2, INTEL_MODEL_G33, "Q35G"},
{0x29d2, INTEL_MODEL_G33, "Q33G"},
{0x2a42, INTEL_TYPE_GM45, "GM45"},
{0x2e02, INTEL_TYPE_G45, "IGD"},
{0x2e12, INTEL_TYPE_G45, "Q45"},
{0x2e22, INTEL_TYPE_G45, "G45"},
{0x2e32, INTEL_TYPE_G45, "G41"},
{0x2e42, INTEL_TYPE_G45, "B43"},
{0x2e92, INTEL_TYPE_G45, "B43"},
{0x2a42, INTEL_MODEL_GM45, "GM45"},
{0x2e02, INTEL_MODEL_G45, "IGD"},
{0x2e12, INTEL_MODEL_G45, "Q45"},
{0x2e22, INTEL_MODEL_G45, "G45"},
{0x2e32, INTEL_MODEL_G45, "G41"},
{0x2e42, INTEL_MODEL_G45, "B43"},
{0x2e92, INTEL_MODEL_G45, "B43"},
{0xa001, INTEL_TYPE_IGDG, "Atom_Dx10"},
{0xa011, INTEL_TYPE_IGDGM, "Atom_N4x0"},
{0xa001, INTEL_MODEL_PINE, "Atom_Dx10"},
{0xa011, INTEL_MODEL_PINEM, "Atom_N4x0"},
{0x0042, INTEL_TYPE_ILKG, "IronLake Desktop"},
{0x0046, INTEL_TYPE_ILKGM, "IronLake Mobile"},
{0x0046, INTEL_TYPE_ILKGM, "IronLake Mobile"},
{0x0046, INTEL_TYPE_ILKGM, "IronLake Mobile"},
{0x0042, INTEL_MODEL_ILKG, "IronLake Desktop"},
{0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"},
{0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"},
{0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"},
{0x0102, INTEL_TYPE_SNBG, "SandyBridge Desktop GT1"},
{0x0112, INTEL_TYPE_SNBG, "SandyBridge Desktop GT2"},
{0x0122, INTEL_TYPE_SNBG, "SandyBridge Desktop GT2+"},
{0x0106, INTEL_TYPE_SNBGM, "SandyBridge Mobile GT1"},
{0x0116, INTEL_TYPE_SNBGM, "SandyBridge Mobile GT2"},
{0x0126, INTEL_TYPE_SNBGM, "SandyBridge Mobile GT2+"},
{0x010a, INTEL_TYPE_SNBGS, "SandyBridge Server"},
// Experimental
#if 0
{0x0102, INTEL_MODEL_SNBG, "SandyBridge Desktop GT1"},
{0x0112, INTEL_MODEL_SNBG, "SandyBridge Desktop GT2"},
{0x0122, INTEL_MODEL_SNBG, "SandyBridge Desktop GT2+"},
{0x0106, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT1"},
{0x0116, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT2"},
{0x0126, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT2+"},
{0x010a, INTEL_MODEL_SNBGS, "SandyBridge Server"},
{0x0152, INTEL_TYPE_IVBG, "IvyBridge Desktop GT1"},
{0x0162, INTEL_TYPE_IVBG, "IvyBridge Desktop GT2"},
{0x0156, INTEL_TYPE_IVBGM, "IvyBridge Mobile GT1"},
{0x0166, INTEL_TYPE_IVBGM, "IvyBridge Mobile GT2"},
{0x015a, INTEL_TYPE_IVBGS, "IvyBridge Server GT1"},
{0x016a, INTEL_TYPE_IVBGS, "IvyBridge Server GT2"},
{0x0152, INTEL_MODEL_IVBG, "IvyBridge Desktop GT1"},
{0x0162, INTEL_MODEL_IVBG, "IvyBridge Desktop GT2"},
{0x0156, INTEL_MODEL_IVBGM, "IvyBridge Mobile GT1"},
{0x0166, INTEL_MODEL_IVBGM, "IvyBridge Mobile GT2"},
{0x015a, INTEL_MODEL_IVBGS, "IvyBridge Server GT1"},
{0x016a, INTEL_MODEL_IVBGS, "IvyBridge Server GT2"},
{0x0412, INTEL_TYPE_IVBG, "Haswell Desktop"},
{0x0416, INTEL_TYPE_IVBGM, "Haswell Mobile"},
{0x0d26, INTEL_TYPE_IVBGM, "Haswell Mobile"},
{0x0412, INTEL_MODEL_HAS, "Haswell Desktop"},
{0x0416, INTEL_MODEL_HASM, "Haswell Mobile"},
{0x0d26, INTEL_MODEL_HASM, "Haswell Mobile"},
{0x0a16, INTEL_MODEL_HASM, "Haswell Mobile"},
{0x0155, INTEL_TYPE_VLVG, "ValleyView Desktop"},
{0x0f30, INTEL_TYPE_VLVGM, "ValleyView Mobile"},
{0x0f31, INTEL_TYPE_VLVGM, "ValleyView Mobile"},
{0x0f32, INTEL_TYPE_VLVGM, "ValleyView Mobile"},
{0x0f33, INTEL_TYPE_VLVGM, "ValleyView Mobile"},
{0x0157, INTEL_TYPE_VLVGM, "ValleyView Mobile"},
{0x0155, INTEL_MODEL_VLV, "ValleyView Desktop"},
{0x0f30, INTEL_MODEL_VLVM, "ValleyView Mobile"},
{0x0f31, INTEL_MODEL_VLVM, "ValleyView Mobile"},
{0x0f32, INTEL_MODEL_VLVM, "ValleyView Mobile"},
{0x0f33, INTEL_MODEL_VLVM, "ValleyView Mobile"},
{0x0157, INTEL_MODEL_VLVM, "ValleyView Mobile"},
#endif
};
int32 api_version = B_CUR_DRIVER_API_VERSION;
@@ -98,7 +98,7 @@ intel_interrupt_handler(void* data)
// Intel changed the PCH register mapping between Sandy Bridge and the
// later generations (Ivy Bridge and up).
if (info.device_type.InFamily(INTEL_TYPE_SNB)) {
if (info.device_type.InGroup(INTEL_GROUP_SNB)) {
mask = hasPCH ? PCH_INTERRUPT_VBLANK_PIPEA_SNB
: INTERRUPT_VBLANK_PIPEA;
if ((identity & mask) != 0) {
@@ -287,7 +287,7 @@ intel_extreme_init(intel_info &info)
int fbIndex = 0;
int mmioIndex = 1;
if (info.device_type.InFamily(INTEL_TYPE_9xx)) {
if (info.device_type.Generation() >= 3) {
// For some reason Intel saw the need to change the order of the
// mappings with the introduction of the i9xx family
mmioIndex = 0;
@@ -316,12 +316,16 @@ intel_extreme_init(intel_info &info)
return info.registers_area;
}
ERROR("Init Intel generation %" B_PRId32 " GPU %s PCH split.\n",
info.device_type.Generation(),
info.device_type.HasPlatformControlHub() ? "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()) {
// PCH based platforms (IronLake and up)
// PCH based platforms (IronLake through ultra-low-power Broadwells)
blocks[REGISTER_BLOCK(REGS_NORTH_SHARED)]
= PCH_NORTH_SHARED_REGISTER_BASE;
blocks[REGISTER_BLOCK(REGS_NORTH_PIPE_AND_PORT)]
@@ -346,14 +350,24 @@ intel_extreme_init(intel_info &info)
= ICH_PORT_REGISTER_BASE;
}
// "I nearly got violent with the hw guys when they told me..."
if (info.device_type.InFamily(INTEL_TYPE_VLV)) {
TRACE("%s: ValleyView MMIO offset engaged\n", __func__);
blocks[REGISTER_BLOCK(REGS_NORTH_PLANE_CONTROL)] += VLV_DISPLAY_BASE;
blocks[REGISTER_BLOCK(REGS_NORTH_SHARED)] += VLV_DISPLAY_BASE;
// Everything in the display PRM gets +0x180000
if (info.device_type.InGroup(INTEL_GROUP_VLV)) {
// "I nearly got violent with the hw guys when they told me..."
blocks[REGISTER_BLOCK(REGS_SOUTH_SHARED)] += VLV_DISPLAY_BASE;
blocks[REGISTER_BLOCK(REGS_SOUTH_TRANSCODER_PORT)] += VLV_DISPLAY_BASE;
}
TRACE("REGS_NORTH_SHARED: 0x%X\n",
blocks[REGISTER_BLOCK(REGS_NORTH_SHARED)]);
TRACE("REGS_NORTH_PIPE_AND_PORT: 0x%X\n",
blocks[REGISTER_BLOCK(REGS_NORTH_PIPE_AND_PORT)]);
TRACE("REGS_NORTH_PLANE_CONTROL: 0x%X\n",
blocks[REGISTER_BLOCK(REGS_NORTH_PLANE_CONTROL)]);
TRACE("REGS_SOUTH_SHARED: 0x%X\n",
blocks[REGISTER_BLOCK(REGS_SOUTH_SHARED)]);
TRACE("REGS_SOUTH_TRANSCODER_PORT: 0x%X\n",
blocks[REGISTER_BLOCK(REGS_SOUTH_TRANSCODER_PORT)]);
// make sure bus master, memory-mapped I/O, and frame buffer is enabled
set_pci_config(info.pci, PCI_command, 2, get_pci_config(info.pci,
PCI_command, 2) | PCI_command_io | PCI_command_memory
@@ -391,13 +405,16 @@ intel_extreme_init(intel_info &info)
info.shared_info->frame_buffer = 0;
info.shared_info->dpms_mode = B_DPMS_ON;
// Pull VBIOS panel mode for later use
info.shared_info->got_vbt = get_lvds_mode_from_bios(
&info.shared_info->current_mode);
&info.shared_info->panel_mode);
/* at least 855gm can't drive more than one head at time */
if (info.device_type.InFamily(INTEL_TYPE_8xx))
if (info.device_type.InFamily(INTEL_FAMILY_8xx))
info.shared_info->single_head_locked = 1;
if (info.device_type.InFamily(INTEL_TYPE_9xx)) {
if (info.device_type.InFamily(INTEL_FAMILY_9xx)
| info.device_type.InFamily(INTEL_FAMILY_SER5)) {
info.shared_info->pll_info.reference_frequency = 96000; // 96 kHz
info.shared_info->pll_info.max_frequency = 400000;
// 400 MHz RAM DAC speed
@@ -457,6 +474,18 @@ intel_extreme_init(intel_info &info)
init_interrupt_handler(info);
if (info.device_type.HasPlatformControlHub()) {
if (info.device_type.Generation() == 5) {
info.shared_info->fdi_link_frequency = (read32(info, FDI_PLL_BIOS_0)
& FDI_PLL_FB_CLOCK_MASK) + 2;
info.shared_info->fdi_link_frequency *= 100;
} else {
info.shared_info->fdi_link_frequency = 2700;
}
} else {
info.shared_info->fdi_link_frequency = 0;
}
TRACE("%s: completed successfully!\n", __func__);
return B_OK;
}
@@ -70,7 +70,7 @@ find_reg(const intel_info& info, uint32 target)
}
extern bool get_lvds_mode_from_bios(display_mode *shared_info);
extern bool get_lvds_mode_from_bios(display_mode *mode);
extern status_t intel_free_memory(intel_info& info, addr_t offset);
extern status_t intel_allocate_memory(intel_info& info, size_t size,
size_t alignment, uint32 flags, addr_t* _offset,
@@ -31,19 +31,19 @@ intel_en_gating(intel_info &info)
if (info.pci->device_id == 0x2a02 || info.pci->device_id == 0x2a12) {
TRACE("i965GM/i965GME quirk\n");
write32(info, 0x6204, (1L << 29));
} else if (info.device_type.InGroup(INTEL_TYPE_SNB)) {
} else if (info.device_type.InGroup(INTEL_GROUP_SNB)) {
TRACE("SandyBridge clock gating\n");
write32(info, 0x42020, (1L << 28) | (1L << 7) | (1L << 5));
} else if (info.device_type.InGroup(INTEL_TYPE_IVB)) {
} else if (info.device_type.InGroup(INTEL_GROUP_IVB)) {
TRACE("IvyBridge clock gating\n");
write32(info, 0x42020, (1L << 28));
} else if (info.device_type.InGroup(INTEL_TYPE_VLV)) {
} else if (info.device_type.InGroup(INTEL_GROUP_VLV)) {
TRACE("ValleyView clock gating\n");
write32(info, VLV_DISPLAY_BASE + 0x6200, (1L << 28));
} else if (info.device_type.InGroup(INTEL_TYPE_ILK)) {
} else if (info.device_type.InGroup(INTEL_GROUP_ILK)) {
TRACE("IronLake clock gating\n");
write32(info, 0x42020, (1L << 7) | (1L << 5));
} else if (info.device_type.InGroup(INTEL_TYPE_G4x)) {
} else if (info.device_type.InGroup(INTEL_GROUP_G4x)) {
TRACE("G4x clock gating\n");
write32(info, 0x6204, 0);
write32(info, 0x6208, (1L << 9) | (1L << 7) | (1L << 6));
@@ -70,8 +70,8 @@ intel_en_downclock(intel_info &info)
{
CALLED();
if (!info.device_type.InGroup(INTEL_TYPE_SNB)
&& !info.device_type.InGroup(INTEL_TYPE_IVB)) {
if (!info.device_type.InGroup(INTEL_GROUP_SNB)
&& !info.device_type.InGroup(INTEL_GROUP_IVB)) {
TRACE("%s: Downclocking not supported on this chipset.\n", __func__);
return B_NOT_ALLOWED;
}