* Add preliminary support for one SandyBridge mobile integrated graphics device

(the one in my new ThinkPad X1). The PLL is still off a bit so it has a few
  blurry stripes, but EDID and mode setting basically works.
* Starting with IronLake the north/south bridge or (G)MCH/ICH setup was moved
  into a platform control hub (PCH) which means that many registers previously
  located in the GMCH are now in the PCH and have a new address.
* I'm committing this mostly because this way the additions are more easy to
  follow. It is a bit messy and I'll clean it up more and possibly make it a
  bit more generic. Also most of these changes actually apply to IronLake and up
  and aren't SandyBridge specific, so a few of those additions will still get a
  broader scope and new chips will be added.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42839 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2011-10-13 09:07:33 +00:00
parent c6e876fc85
commit e436a27e5f
6 changed files with 249 additions and 62 deletions

View File

@ -18,13 +18,13 @@
#define VENDOR_ID_INTEL 0x8086
#define INTEL_TYPE_FAMILY_MASK 0xf000
#define INTEL_TYPE_GROUP_MASK 0xfff0
#define INTEL_TYPE_MODEL_MASK 0xffff
#define INTEL_TYPE_FAMILY_MASK 0x000f0000
#define INTEL_TYPE_GROUP_MASK 0x000ffff0
#define INTEL_TYPE_MODEL_MASK 0x000fffff
// families
#define INTEL_TYPE_7xx 0x1000
#define INTEL_TYPE_8xx 0x2000
#define INTEL_TYPE_9xx 0x4000
#define INTEL_TYPE_7xx 0x00010000
#define INTEL_TYPE_8xx 0x00020000
#define INTEL_TYPE_9xx 0x00040000
// groups
#define INTEL_TYPE_83x (INTEL_TYPE_8xx | 0x0010)
#define INTEL_TYPE_85x (INTEL_TYPE_8xx | 0x0020)
@ -34,6 +34,7 @@
#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_SNB (INTEL_TYPE_9xx | 0x1000)
// models
#define INTEL_TYPE_MOBILE 0x0008
#define INTEL_TYPE_915 (INTEL_TYPE_91x)
@ -47,6 +48,8 @@
#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_SNBG (INTEL_TYPE_SNB)
#define INTEL_TYPE_SNBGM (INTEL_TYPE_SNB | INTEL_TYPE_MOBILE)
#define DEVICE_NAME "intel_extreme"
#define INTEL_ACCELERANT_NAME "intel_extreme.accelerant"
@ -218,6 +221,59 @@ struct intel_free_graphics_memory {
#define G4X_STOLEN_MEMORY_224MB 0xc0
#define G4X_STOLEN_MEMORY_352MB 0xd0
// 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.).
#define PCH_DE_INTERRUPT_ENABLE 0x4400c // INTEL_INTERRUPT_ENABLED
#define PCH_DISPLAY_A_ANALOG_PORT 0xe1100 // INTEL_DISPLAY_A_ANALOG_PORT
#define PCH_DISPLAY_LVDS_PORT 0xe1180 // INTEL_DISPLAY_LVDS_PORT
#define PCH_I2C_IO_A 0xc5010 // INTEL_I2C_IO_A
#define PCH_I2C_IO_C 0xc5018 // INTEL_I2C_IO_C
#define PCH_DISPLAY_A_PLL 0xc6014 // INTEL_DISPLAY_A_PLL
#define PCH_DISPLAY_B_PLL 0xc6018 // INTEL_DISPLAY_B_PLL
#define PCH_DISPLAY_A_PLL_DIVISOR_0 0xc6040 // INTEL_DISPLAY_A_PLL_DIVISOR_0
#define PCH_DISPLAY_A_PLL_DIVISOR_1 0xc6044 // INTEL_DISPLAY_A_PLL_DIVISOR_1
#define PCH_DISPLAY_B_PLL_DIVISOR_0 0xc6048 // INTEL_DISPLAY_B_PLL_DIVISOR_0
#define PCH_DISPLAY_B_PLL_DIVISOR_1 0xc604c // INTEL_DISPLAY_B_PLL_DIVISOR_1
#define PCH_TRANSCODER_A_HTOTAL 0xe0000 // INTEL_DISPLAY_A_HTOTAL
#define PCH_TRANSCODER_A_HBLANK 0xe0004 // INTEL_DISPLAY_A_HBLANK
#define PCH_TRANSCODER_A_HSYNC 0xe0008 // INTEL_DISPLAY_A_HSYNC
#define PCH_TRANSCODER_A_VTOTAL 0xe000c // INTEL_DISPLAY_A_VTOTAL
#define PCH_TRANSCODER_A_VBLANK 0xe0010 // INTEL_DISPLAY_A_VBLANK
#define PCH_TRANSCODER_A_VSYNC 0xe0014 // INTEL_DISPLAY_A_VSYNC
#define PCH_TRANSCODER_B_HTOTAL 0xe1000 // INTEL_DISPLAY_B_HTOTAL
#define PCH_TRANSCODER_B_HBLANK 0xe1004 // INTEL_DISPLAY_B_HBLANK
#define PCH_TRANSCODER_B_HSYNC 0xe1008 // INTEL_DISPLAY_B_HSYNC
#define PCH_TRANSCODER_B_VTOTAL 0xe100c // INTEL_DISPLAY_B_VTOTAL
#define PCH_TRANSCODER_B_VBLANK 0xe1010 // INTEL_DISPLAY_B_VBLANK
#define PCH_TRANSCODER_B_VSYNC 0xe1014 // INTEL_DISPLAY_B_VSYNC
// SandyBridge (SNB)
#define SNB_GRAPHICS_MEMORY_CONTROL 0x50
#define SNB_STOLEN_MEMORY_MASK 0xf8
#define SNB_STOLEN_MEMORY_32MB (1 << 3)
#define SNB_STOLEN_MEMORY_64MB (2 << 3)
#define SNB_STOLEN_MEMORY_96MB (3 << 3)
#define SNB_STOLEN_MEMORY_128MB (4 << 3)
#define SNB_STOLEN_MEMORY_160MB (5 << 3)
#define SNB_STOLEN_MEMORY_192MB (6 << 3)
#define SNB_STOLEN_MEMORY_224MB (7 << 3)
#define SNB_STOLEN_MEMORY_256MB (8 << 3)
#define SNB_STOLEN_MEMORY_288MB (9 << 3)
#define SNB_STOLEN_MEMORY_320MB (10 << 3)
#define SNB_STOLEN_MEMORY_352MB (11 << 3)
#define SNB_STOLEN_MEMORY_384MB (12 << 3)
#define SNB_STOLEN_MEMORY_416MB (13 << 3)
#define SNB_STOLEN_MEMORY_448MB (14 << 3)
#define SNB_STOLEN_MEMORY_480MB (15 << 3)
#define SNB_STOLEN_MEMORY_512MB (16 << 3)
#define SNB_GTT_SIZE_MASK (3 << 8)
#define SNB_GTT_SIZE_NONE (0 << 8)
#define SNB_GTT_SIZE_1MB (1 << 8)
#define SNB_GTT_SIZE_2MB (2 << 8)
// graphics page translation table
#define INTEL_PAGE_TABLE_CONTROL 0x02020

View File

@ -115,7 +115,8 @@ get_accelerant_hook(uint32 feature, void *data)
|| 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_IGD)
|| gInfo->shared_info->device_type.InGroup(INTEL_TYPE_SNB))
return NULL;
return (void*)intel_allocate_overlay_buffer;

View File

@ -132,7 +132,8 @@ set_frame_buffer_base()
}
if (sharedInfo.device_type.InGroup(INTEL_TYPE_96x)
|| sharedInfo.device_type.InGroup(INTEL_TYPE_G4x)) {
|| sharedInfo.device_type.InGroup(INTEL_TYPE_G4x)
|| sharedInfo.device_type.InGroup(INTEL_TYPE_SNB)) {
write32(baseRegister, mode.v_display_start * sharedInfo.bytes_per_row
+ mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8);
read32(baseRegister);
@ -153,8 +154,10 @@ set_frame_buffer_base()
status_t
create_mode_list(void)
{
bool isSNB = gInfo->shared_info->device_type.InGroup(INTEL_TYPE_SNB);
i2c_bus bus;
bus.cookie = (void*)INTEL_I2C_IO_A;
bus.cookie = (void*)(isSNB ? PCH_I2C_IO_A : INTEL_I2C_IO_A);
bus.set_signals = &set_i2c_signals;
bus.get_signals = &get_i2c_signals;
ddc2_init_timing(&bus);
@ -166,7 +169,7 @@ create_mode_list(void)
} else {
TRACE(("intel_extreme: getting EDID on port A (analog) failed : %s. "
"Trying on port C (lvds)\n", strerror(error)));
bus.cookie = (void*)INTEL_I2C_IO_C;
bus.cookie = (void*)(isSNB ? PCH_I2C_IO_C : INTEL_I2C_IO_C);
error = ddc2_read_edid1(&bus, &gInfo->edid_info, NULL, NULL);
if (error == B_OK) {
edid_dump(&gInfo->edid_info);
@ -234,7 +237,16 @@ get_pll_limits(pll_limits &limits)
// Note, the limits are taken from the X driver; they have not yet been
// tested
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_G4x)) {
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_SNB)) {
// TODO: support LVDS output limits as well
static const 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
};
limits = kLimits;
} else if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_G4x)) {
// TODO: support LVDS output limits as well
static const pll_limits kLimits = {
// p, p1, p2, high, n, m, m1, m2
@ -312,8 +324,12 @@ compute_pll_divisors(const display_mode &current, pll_divisors& divisors,
TRACE(("required MHz: %g\n", requestedPixelClock));
bool isSNB = gInfo->shared_info->device_type.InGroup(INTEL_TYPE_SNB);
if (isLVDS) {
if ((read32(INTEL_DISPLAY_LVDS_PORT) & LVDS_CLKB_POWER_MASK)
int targetRegister
= isSNB ? PCH_DISPLAY_LVDS_PORT : INTEL_DISPLAY_LVDS_PORT;
if ((read32(targetRegister) & LVDS_CLKB_POWER_MASK)
== LVDS_CLKB_POWER_UP)
divisors.post2 = LVDS_POST2_RATE_FAST;
else
@ -402,6 +418,26 @@ retrieve_current_mode(display_mode& mode, uint32 pllRegister)
vSyncRegister = INTEL_DISPLAY_B_VSYNC;
imageSizeRegister = INTEL_DISPLAY_B_IMAGE_SIZE;
controlRegister = INTEL_DISPLAY_B_CONTROL;
} else if (pllRegister == PCH_DISPLAY_A_PLL) {
pllDivisor = read32((pll & DISPLAY_PLL_DIVISOR_1) != 0
? PCH_DISPLAY_A_PLL_DIVISOR_1 : PCH_DISPLAY_A_PLL_DIVISOR_0);
hTotalRegister = PCH_TRANSCODER_A_HTOTAL;
vTotalRegister = PCH_TRANSCODER_A_VTOTAL;
hSyncRegister = PCH_TRANSCODER_A_HSYNC;
vSyncRegister = PCH_TRANSCODER_A_VSYNC;
imageSizeRegister = INTEL_DISPLAY_A_IMAGE_SIZE;
controlRegister = INTEL_DISPLAY_A_CONTROL;
} else if (pllRegister == PCH_DISPLAY_B_PLL) {
pllDivisor = read32((pll & DISPLAY_PLL_DIVISOR_1) != 0
? PCH_DISPLAY_B_PLL_DIVISOR_1 : PCH_DISPLAY_B_PLL_DIVISOR_0);
hTotalRegister = PCH_TRANSCODER_B_HTOTAL;
vTotalRegister = PCH_TRANSCODER_B_VTOTAL;
hSyncRegister = PCH_TRANSCODER_B_HSYNC;
vSyncRegister = PCH_TRANSCODER_B_VSYNC;
imageSizeRegister = INTEL_DISPLAY_B_IMAGE_SIZE;
controlRegister = INTEL_DISPLAY_B_CONTROL;
} else {
// TODO: not supported
return;
@ -529,9 +565,12 @@ retrieve_current_mode(display_mode& mode, uint32 pllRegister)
void
save_lvds_mode(void)
{
bool isSNB = gInfo->shared_info->device_type.InGroup(INTEL_TYPE_SNB);
// dump currently programmed mode.
display_mode biosMode;
retrieve_current_mode(biosMode, INTEL_DISPLAY_B_PLL);
retrieve_current_mode(biosMode,
isSNB ? PCH_DISPLAY_B_PLL : INTEL_DISPLAY_B_PLL);
gInfo->lvds_panel_mode = biosMode;
}
@ -645,7 +684,7 @@ intel_set_display_mode(display_mode *mode)
// centering, since the data from propose_display_mode will not actually be
// used as is in this case.
if (sanitize_display_mode(target)) {
TRACE(("intel_extreme: invalid mode set!"));
TRACE(("intel_extreme: invalid mode set!\n"));
return B_BAD_VALUE;
}
@ -710,6 +749,9 @@ if (first) {
write32(INTEL_VGA_DISPLAY_CONTROL, VGA_DISPLAY_DISABLED);
read32(INTEL_VGA_DISPLAY_CONTROL);
bool isSNB = gInfo->shared_info->device_type.InGroup(INTEL_TYPE_SNB);
int targetRegister;
if ((gInfo->head_mode & HEAD_MODE_B_DIGITAL) != 0) {
// For LVDS panels, we actually always set the native mode in hardware
// Then we use the panel fitter to scale the picture to that.
@ -761,9 +803,11 @@ if (first) {
// Compute bitmask from p1 value
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) {
dpll |= (1 << (divisors.post1 - 1)) << DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT;
dpll |= (1 << (divisors.post1 - 1))
<< DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT;
} else {
dpll |= (1 << (divisors.post1 - 1)) << DISPLAY_PLL_POST1_DIVISOR_SHIFT;
dpll |= (1 << (divisors.post1 - 1))
<< DISPLAY_PLL_POST1_DIVISOR_SHIFT;
}
switch (divisors.post2) {
case 5:
@ -785,7 +829,8 @@ if (first) {
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
} else {
write32(INTEL_DISPLAY_B_PLL_DIVISOR_0,
write32(isSNB ? PCH_DISPLAY_B_PLL_DIVISOR_0
: INTEL_DISPLAY_B_PLL_DIVISOR_0,
(((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_N_DIVISOR_MASK)
| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
@ -793,13 +838,16 @@ if (first) {
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_M2_DIVISOR_MASK));
}
write32(INTEL_DISPLAY_B_PLL, dpll & ~DISPLAY_PLL_ENABLED);
read32(INTEL_DISPLAY_B_PLL);
targetRegister = isSNB ? PCH_DISPLAY_B_PLL : INTEL_DISPLAY_B_PLL;
write32(targetRegister, dpll & ~DISPLAY_PLL_ENABLED);
read32(targetRegister);
spin(150);
}
uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT)
| LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT;
targetRegister
= isSNB ? PCH_DISPLAY_LVDS_PORT : INTEL_DISPLAY_LVDS_PORT;
uint32 lvds = read32(targetRegister) | LVDS_PORT_EN
| LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT;
lvds |= LVDS_18BIT_DITHER;
// TODO: do not do this if the connected panel is 24-bit
@ -815,8 +863,8 @@ if (first) {
else
lvds &= ~( LVDS_B0B3PAIRS_POWER_UP | LVDS_CLKB_POWER_UP);
write32(INTEL_DISPLAY_LVDS_PORT, lvds);
read32(INTEL_DISPLAY_LVDS_PORT);
write32(targetRegister, lvds);
read32(targetRegister);
if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) {
write32(INTEL_DISPLAY_B_PLL_DIVISOR_0,
@ -825,7 +873,8 @@ if (first) {
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
} else {
write32(INTEL_DISPLAY_B_PLL_DIVISOR_0,
write32(isSNB ? PCH_DISPLAY_B_PLL_DIVISOR_0
: INTEL_DISPLAY_B_PLL_DIVISOR_0,
(((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_N_DIVISOR_MASK)
| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
@ -834,8 +883,9 @@ if (first) {
& DISPLAY_PLL_M2_DIVISOR_MASK));
}
write32(INTEL_DISPLAY_B_PLL, dpll);
read32(INTEL_DISPLAY_B_PLL);
targetRegister = isSNB ? PCH_DISPLAY_B_PLL : INTEL_DISPLAY_B_PLL;
write32(targetRegister, dpll);
read32(targetRegister);
// Wait for the clocks to stabilize
spin(150);
@ -855,9 +905,9 @@ if (first) {
write32(INTEL_DISPLAY_B_PLL_MULTIPLIER_DIVISOR, (0 << 24)
| ((pixelMultiply - 1) << 8));
} else
write32(INTEL_DISPLAY_B_PLL, dpll);
write32(targetRegister, dpll);
read32(INTEL_DISPLAY_B_PLL);
read32(targetRegister);
spin(150);
// update timing parameters
@ -878,14 +928,14 @@ if (first) {
+ (hardwareTarget.timing.h_total
- target.timing.h_display) / 2;
write32(INTEL_DISPLAY_B_HTOTAL,
write32(isSNB ? PCH_TRANSCODER_B_HTOTAL : INTEL_DISPLAY_B_HTOTAL,
((uint32)(hardwareTarget.timing.h_total - 1) << 16)
| ((uint32)target.timing.h_display - 1));
write32(INTEL_DISPLAY_B_HBLANK,
write32(isSNB ? PCH_TRANSCODER_B_HBLANK : INTEL_DISPLAY_B_HBLANK,
((uint32)(hardwareTarget.timing.h_total - borderWidth / 2 - 1)
<< 16)
| ((uint32)target.timing.h_display + borderWidth / 2 - 1));
write32(INTEL_DISPLAY_B_HSYNC,
write32(isSNB ? PCH_TRANSCODER_B_HSYNC : INTEL_DISPLAY_B_HSYNC,
((uint32)(syncCenter + syncWidth / 2 - 1) << 16)
| ((uint32)syncCenter - syncWidth / 2 - 1));
@ -899,16 +949,16 @@ if (first) {
+ (hardwareTarget.timing.v_total
- target.timing.v_display) / 2;
write32(INTEL_DISPLAY_B_VTOTAL,
write32(isSNB ? PCH_TRANSCODER_B_VTOTAL : INTEL_DISPLAY_B_VTOTAL,
((uint32)(hardwareTarget.timing.v_total - 1) << 16)
| ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_B_VBLANK,
write32(isSNB ? PCH_TRANSCODER_B_VBLANK : INTEL_DISPLAY_B_VBLANK,
((uint32)(hardwareTarget.timing.v_total - borderHeight / 2 - 1)
<< 16)
| ((uint32)target.timing.v_display
+ borderHeight / 2 - 1));
write32(INTEL_DISPLAY_B_VSYNC, ((uint32)(syncCenter
+ syncHeight / 2 - 1) << 16)
write32(isSNB ? PCH_TRANSCODER_B_VSYNC : INTEL_DISPLAY_B_VSYNC,
((uint32)(syncCenter + syncHeight / 2 - 1) << 16)
| ((uint32)syncCenter - syncHeight / 2 - 1));
// This is useful for debugging: it sets the border to red, so you
@ -916,23 +966,23 @@ if (first) {
// sync)
// write32(0x61020, 0x00FF0000);
} else {
write32(INTEL_DISPLAY_B_HTOTAL,
write32(isSNB ? PCH_TRANSCODER_B_HTOTAL : INTEL_DISPLAY_B_HTOTAL,
((uint32)(target.timing.h_total - 1) << 16)
| ((uint32)target.timing.h_display - 1));
write32(INTEL_DISPLAY_B_HBLANK,
write32(isSNB ? PCH_TRANSCODER_B_HBLANK : INTEL_DISPLAY_B_HBLANK,
((uint32)(target.timing.h_total - 1) << 16)
| ((uint32)target.timing.h_display - 1));
write32(INTEL_DISPLAY_B_HSYNC, (
(uint32)(target.timing.h_sync_end - 1) << 16)
write32(isSNB ? PCH_TRANSCODER_B_HSYNC : INTEL_DISPLAY_B_HSYNC,
((uint32)(target.timing.h_sync_end - 1) << 16)
| ((uint32)target.timing.h_sync_start - 1));
write32(INTEL_DISPLAY_B_VTOTAL,
write32(isSNB ? PCH_TRANSCODER_B_VTOTAL : INTEL_DISPLAY_B_VTOTAL,
((uint32)(target.timing.v_total - 1) << 16)
| ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_B_VBLANK,
write32(isSNB ? PCH_TRANSCODER_B_VBLANK : INTEL_DISPLAY_B_VBLANK,
((uint32)(target.timing.v_total - 1) << 16)
| ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_B_VSYNC, (
write32(isSNB ? PCH_TRANSCODER_B_VSYNC : INTEL_DISPLAY_B_VSYNC, (
(uint32)(target.timing.v_sync_end - 1) << 16)
| ((uint32)target.timing.v_sync_start - 1));
}
@ -966,7 +1016,8 @@ if (first) {
| (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT)
& DISPLAY_PLL_IGD_M2_DIVISOR_MASK));
} else {
write32(INTEL_DISPLAY_A_PLL_DIVISOR_0,
write32(isSNB ? PCH_DISPLAY_A_PLL_DIVISOR_0
: INTEL_DISPLAY_A_PLL_DIVISOR_0,
(((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT)
& DISPLAY_PLL_N_DIVISOR_MASK)
| (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT)
@ -1008,31 +1059,32 @@ if (first) {
pll |= DISPLAY_PLL_POST1_DIVIDE_2;
}
write32(INTEL_DISPLAY_A_PLL, pll);
read32(INTEL_DISPLAY_A_PLL);
targetRegister = isSNB ? PCH_DISPLAY_A_PLL : INTEL_DISPLAY_A_PLL;
write32(targetRegister, pll);
read32(targetRegister);
spin(150);
write32(INTEL_DISPLAY_A_PLL, pll);
read32(INTEL_DISPLAY_A_PLL);
write32(targetRegister, pll);
read32(targetRegister);
spin(150);
// update timing parameters
write32(INTEL_DISPLAY_A_HTOTAL,
write32(isSNB ? PCH_TRANSCODER_A_HTOTAL : INTEL_DISPLAY_A_HTOTAL,
((uint32)(target.timing.h_total - 1) << 16)
| ((uint32)target.timing.h_display - 1));
write32(INTEL_DISPLAY_A_HBLANK,
write32(isSNB ? PCH_TRANSCODER_A_HBLANK : INTEL_DISPLAY_A_HBLANK,
((uint32)(target.timing.h_total - 1) << 16)
| ((uint32)target.timing.h_display - 1));
write32(INTEL_DISPLAY_A_HSYNC,
write32(isSNB ? PCH_TRANSCODER_A_HSYNC : INTEL_DISPLAY_A_HSYNC,
((uint32)(target.timing.h_sync_end - 1) << 16)
| ((uint32)target.timing.h_sync_start - 1));
write32(INTEL_DISPLAY_A_VTOTAL,
write32(isSNB ? PCH_TRANSCODER_A_VTOTAL : INTEL_DISPLAY_A_VTOTAL,
((uint32)(target.timing.v_total - 1) << 16)
| ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_A_VBLANK,
write32(isSNB ? PCH_TRANSCODER_A_VBLANK : INTEL_DISPLAY_A_VBLANK,
((uint32)(target.timing.v_total - 1) << 16)
| ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_A_VSYNC,
write32(isSNB ? PCH_TRANSCODER_A_VSYNC : INTEL_DISPLAY_A_VSYNC,
((uint32)(target.timing.v_sync_end - 1) << 16)
| ((uint32)target.timing.v_sync_start - 1));
@ -1040,8 +1092,10 @@ if (first) {
((uint32)(target.timing.h_display - 1) << 16)
| ((uint32)target.timing.v_display - 1));
write32(INTEL_DISPLAY_A_ANALOG_PORT,
(read32(INTEL_DISPLAY_A_ANALOG_PORT)
targetRegister
= isSNB ? PCH_DISPLAY_A_ANALOG_PORT : INTEL_DISPLAY_A_ANALOG_PORT;
write32(targetRegister,
(read32(targetRegister)
& ~(DISPLAY_MONITOR_POLARITY_MASK
| DISPLAY_MONITOR_VGA_POLARITY))
| ((target.timing.flags & B_POSITIVE_HSYNC) != 0
@ -1097,7 +1151,9 @@ intel_get_display_mode(display_mode *_currentMode)
{
TRACE(("intel_get_display_mode()\n"));
retrieve_current_mode(*_currentMode, INTEL_DISPLAY_A_PLL);
bool isSNB = gInfo->shared_info->device_type.InGroup(INTEL_TYPE_SNB);
retrieve_current_mode(*_currentMode,
isSNB ? PCH_DISPLAY_A_PLL : INTEL_DISPLAY_A_PLL);
return B_OK;
}

View File

@ -77,9 +77,11 @@ const struct supported_device {
{0x2e30, 0x2e32, INTEL_TYPE_G45, "G41"},
{0x2e40, 0x2e42, INTEL_TYPE_G45, "B43"},
{0x2e90, 0x2e92, INTEL_TYPE_G45, "B43"},
{0xa000, 0xa001, INTEL_TYPE_IGDG, "Atom_Dx10"},
{0xa010, 0xa011, INTEL_TYPE_IGDGM, "Atom_N4x0"},
{0x0104, 0x0126, INTEL_TYPE_SNBGM, "SNBGM"},
};
struct intel_info {
@ -131,8 +133,11 @@ static void
determine_memory_sizes(intel_info &info, size_t &gttSize, size_t &stolenSize)
{
// read stolen memory from the PCI configuration of the PCI bridge
uint16 memoryConfig = get_pci_config(info.bridge,
INTEL_GRAPHICS_MEMORY_CONTROL, 2);
uint8 controlRegister = INTEL_GRAPHICS_MEMORY_CONTROL;
if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB)
controlRegister = SNB_GRAPHICS_MEMORY_CONTROL;
uint16 memoryConfig = get_pci_config(info.bridge, controlRegister, 2);
size_t memorySize = 1 << 20; // 1 MB
gttSize = 0;
stolenSize = 0;
@ -178,6 +183,18 @@ determine_memory_sizes(intel_info &info, size_t &gttSize, size_t &stolenSize)
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
@ -191,7 +208,7 @@ determine_memory_sizes(intel_info &info, size_t &gttSize, size_t &stolenSize)
} 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));
TRACE("frame buffer size %lu MB\n", frameBufferSize >> 20);
gttSize = frameBufferSize / 1024;
}
@ -214,6 +231,57 @@ 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) {
switch (memoryConfig & SNB_STOLEN_MEMORY_MASK) {
case SNB_STOLEN_MEMORY_32MB:
memorySize *= 32;
break;
case SNB_STOLEN_MEMORY_64MB:
memorySize *= 64;
break;
case SNB_STOLEN_MEMORY_96MB:
memorySize *= 96;
break;
case SNB_STOLEN_MEMORY_128MB:
memorySize *= 128;
break;
case SNB_STOLEN_MEMORY_160MB:
memorySize *= 160;
break;
case SNB_STOLEN_MEMORY_192MB:
memorySize *= 192;
break;
case SNB_STOLEN_MEMORY_224MB:
memorySize *= 224;
break;
case SNB_STOLEN_MEMORY_256MB:
memorySize *= 256;
break;
case SNB_STOLEN_MEMORY_288MB:
memorySize *= 288;
break;
case SNB_STOLEN_MEMORY_320MB:
memorySize *= 320;
break;
case SNB_STOLEN_MEMORY_352MB:
memorySize *= 352;
break;
case SNB_STOLEN_MEMORY_384MB:
memorySize *= 384;
break;
case SNB_STOLEN_MEMORY_416MB:
memorySize *= 416;
break;
case SNB_STOLEN_MEMORY_448MB:
memorySize *= 448;
break;
case SNB_STOLEN_MEMORY_480MB:
memorySize *= 480;
break;
case SNB_STOLEN_MEMORY_512MB:
memorySize *= 512;
break;
}
} else if (info.type == INTEL_TYPE_85x
|| (info.type & INTEL_TYPE_9xx) == INTEL_TYPE_9xx) {
switch (memoryConfig & STOLEN_MEMORY_MASK) {
@ -325,7 +393,8 @@ intel_map(intel_info &info)
return B_ERROR;
if ((info.type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_9xx) {
if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x) {
if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x
|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB) {
info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
+ (2UL << 20);
} else

View File

@ -69,9 +69,11 @@ const struct supported_device {
{0x2e32, INTEL_TYPE_G45, "G41"},
{0x2e42, INTEL_TYPE_G45, "B43"},
{0x2e92, INTEL_TYPE_G45, "B43"},
{0xa001, INTEL_TYPE_IGDG, "Atom_Dx10"},
{0xa011, INTEL_TYPE_IGDGM, "Atom_N4x0"},
{0x0126, INTEL_TYPE_SNBGM, "SNBGM"},
};
int32 api_version = B_CUR_DRIVER_API_VERSION;

View File

@ -257,6 +257,9 @@ intel_extreme_init(intel_info &info)
if (info.pci->device_id == 0x2a02 || info.pci->device_id == 0x2a12) {
dprintf("i965GM/i965GME quirk\n");
write32(info.registers + 0x6204, (1L << 29));
} else if (info.device_type.InGroup(INTEL_TYPE_SNB)) {
dprintf("SNB clock gating\n");
write32(info.registers + 0x42020, (1L << 28) | (1L << 7) | (1L << 5));
} else if (info.device_type.InGroup(INTEL_TYPE_G4x)) {
dprintf("G4x clock gating\n");
write32(info.registers + 0x6204, 0);