diff options
Diffstat (limited to 'src/i830_driver.c')
-rw-r--r-- | src/i830_driver.c | 1654 |
1 files changed, 1378 insertions, 276 deletions
diff --git a/src/i830_driver.c b/src/i830_driver.c index 1fdfeb93..c0fed71f 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -44,6 +44,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. * Authors: Jeff Hartmann <jhartmann@valinux.com> * Abraham van der Merwe <abraham@2d3d.co.za> * David Dawes <dawes@xfree86.org> + * Alan Hourihane <alanh@tungstengraphics.com> */ /* @@ -126,17 +127,24 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. * * 08/2002 Keith Whitwell * - Fix DRI initialisation. - */ -/* + * + * * 08/2002 Alan Hourihane and David Dawes * - Add XVideo support. - */ -/* + * + * * 10/2002 David Dawes * - Add Intel(R) 865G support. + * + * + * 01/2004 Alan Hourihane + * - Add Intel(R) 915G support. + * - Add Dual Head and Clone capabilities. + * - Add lid status checking + * - Fix Xvideo with high-res LFP's + * - Add ARGB HW cursor support */ - #ifndef PRINT_MODE_INFO #define PRINT_MODE_INFO 0 #endif @@ -154,7 +162,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include "micmap.h" #include "fb.h" -#include "regionstr.h" +#include "miscstruct.h" #include "xf86xv.h" #include "Xv.h" #include "vbe.h" @@ -176,6 +184,7 @@ static SymTabRec I830BIOSChipsets[] = { {PCI_CHIP_845_G, "845G"}, {PCI_CHIP_I855_GM, "852GM/855GM"}, {PCI_CHIP_I865_G, "865G"}, + {PCI_CHIP_I915_G, "915G"}, {-1, NULL} }; @@ -184,6 +193,7 @@ static PciChipsets I830BIOSPciChipsets[] = { {PCI_CHIP_845_G, PCI_CHIP_845_G, RES_SHARED_VGA}, {PCI_CHIP_I855_GM, PCI_CHIP_I855_GM, RES_SHARED_VGA}, {PCI_CHIP_I865_G, PCI_CHIP_I865_G, RES_SHARED_VGA}, + {PCI_CHIP_I915_G, PCI_CHIP_I915_G, RES_SHARED_VGA}, {-1, -1, RES_UNDEFINED} }; @@ -203,7 +213,13 @@ typedef enum { OPTION_VIDEO_KEY, OPTION_COLOR_KEY, OPTION_VBE_RESTORE, - OPTION_DISPLAY_INFO + OPTION_DISPLAY_INFO, + OPTION_DEVICE_PRESENCE, + OPTION_MONITOR_LAYOUT, + OPTION_CLONE, + OPTION_CLONE_REFRESH, + OPTION_CHECKLID, + OPTION_FLIP_PRIMARY } I830Opts; static OptionInfoRec I830BIOSOptions[] = { @@ -217,6 +233,12 @@ static OptionInfoRec I830BIOSOptions[] = { {OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE}, {OPTION_VBE_RESTORE, "VBERestore", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_DISPLAY_INFO,"DisplayInfo", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_DEVICE_PRESENCE,"DevicePresence",OPTV_BOOLEAN,{0}, FALSE}, + {OPTION_MONITOR_LAYOUT, "MonitorLayout", OPTV_ANYSTR,{0}, FALSE}, + {OPTION_CLONE, "Clone", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_CLONE_REFRESH,"CloneRefresh",OPTV_INTEGER, {0}, FALSE}, + {OPTION_CHECKLID, "CheckLid", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_FLIP_PRIMARY,"FlipPrimary", OPTV_BOOLEAN, {0}, FALSE}, {-1, NULL, OPTV_NONE, {0}, FALSE} }; /* *INDENT-ON* */ @@ -229,6 +251,11 @@ static Bool I830BIOSSaveScreen(ScreenPtr pScreen, int unblack); static Bool I830BIOSEnterVT(int scrnIndex, int flags); static Bool I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock *block); +static CARD32 I830LidTimer(OsTimerPtr timer, CARD32 now, pointer arg); +static Bool SetPipeAccess(ScrnInfoPtr pScrn); +static Bool IsPrimary(ScrnInfoPtr pScrn); + +extern int I830EntityIndex; #ifdef I830DEBUG @@ -386,6 +413,8 @@ GetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh, int *availRefresh) if (mode & 0x100) return 0; + SetPipeAccess(pScrn); + pVbe->pInt10->num = 0x10; pVbe->pInt10->ax = 0x5f05; pVbe->pInt10->bx = (mode & 0xff) | 0x100; @@ -552,34 +581,103 @@ GetDisplayDevices(ScrnInfoPtr pScrn) return -1; } +/* This is needed for SetDisplayDevices to work correctly on I915G + * and possibly later Video BIOS builds around 3272 (but not sure here). + * So enable for all chipsets now as it has no bad side effects, apart + * from slightly longer startup time. + */ +#define I915G_WORKAROUND + static Bool SetDisplayDevices(ScrnInfoPtr pScrn, int devices) { I830Ptr pI830 = I830PTR(pScrn); vbeInfoPtr pVbe = pI830->pVbe; CARD32 temp; +#ifdef I915G_WORKAROUND + int getmode; + int mode; + switch (pScrn->depth) { + case 8: + mode = 0x30; + break; + case 15: + mode = 0x40; + break; + case 16: + mode = 0x41; + break; + case 24: + mode = 0x50; + break; + default: + mode = 0x30; + break; + } + mode |= (1 << 15) | (1 << 14); +#endif DPRINTF(PFX, "SetDisplayDevices: devices 0x%x\n", devices); +#ifdef I915G_WORKAROUND + if (pI830->bios_version >= 3272) { + VBEGetVBEMode(pVbe, &getmode); + I830VESASetVBEMode(pScrn, mode, NULL); + } +#endif + pVbe->pInt10->num = 0x10; pVbe->pInt10->ax = 0x5f64; pVbe->pInt10->bx = 0x1; pVbe->pInt10->cx = devices; xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) + if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { +#ifdef I915G_WORKAROUND + if (pI830->bios_version >= 3272) + I830VESASetVBEMode(pScrn, getmode, NULL); +#endif return TRUE; - else { - ErrorF("Writing config directly to SWF0\n"); - temp = INREG(SWF0); - OUTREG(SWF0, (temp & ~(0xffff)) | (devices & 0xffff)); - ErrorF("SetDisplayDevices failed. devices is 0x%x instead of 0x%x\n", - GetDisplayDevices(pScrn), devices); - return FALSE; } + +#ifdef I915G_WORKAROUND + if (pI830->bios_version >= 3272) + I830VESASetVBEMode(pScrn, getmode, NULL); +#endif + + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "SetDisplayDevices call failed, writing config directly to SWF0.\n"); + temp = INREG(SWF0); + OUTREG(SWF0, (temp & ~(0xffff)) | (devices & 0xffff)); + + if (GetDisplayDevices(pScrn) != devices) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "SetDisplayDevices failed with devices 0x%x instead of 0x%x\n", + GetDisplayDevices(pScrn), devices); + + return FALSE; +} + +static Bool +GetBIOSVersion(ScrnInfoPtr pScrn, unsigned int *version) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "GetBIOSVersion\n"); + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f01; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f01, pVbe->pInt10->ax)) { + *version = pVbe->pInt10->bx; + return TRUE; + } + + *version = 0; + return FALSE; } -#if 0 static Bool GetDevicePresence(ScrnInfoPtr pScrn, Bool *required, int *attached, int *encoderPresent) @@ -604,7 +702,6 @@ GetDevicePresence(ScrnInfoPtr pScrn, Bool *required, int *attached, } else return FALSE; } -#endif static Bool GetDisplayInfo(ScrnInfoPtr pScrn, int device, Bool *attached, Bool *present, @@ -663,8 +760,10 @@ static const char *displayDevices[] = { "TV", "DFP (digital flat panel)", "LFP (local flat panel)", + "CRT2 (second CRT)", "TV2 (second TV)", "DFP2 (second digital flat panel)", + "LFP2 (second local flat panel)", NULL }; @@ -672,7 +771,7 @@ static const char * DeviceToString(int device) { static int savedDevice = -1; - static int bit = 0; + int bit = 0; const char *name; if (device == -1) { @@ -704,7 +803,7 @@ PrintDisplayDeviceInfo(ScrnInfoPtr pScrn) DPRINTF(PFX, "PrintDisplayDeviceInfo\n"); - displays = pI830->configuredDevices; + displays = pI830->operatingDevices; if (displays == -1) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No active display devices.\n"); @@ -758,7 +857,7 @@ GetPipeSizes(ScrnInfoPtr pScrn) for (n = 0; n < pI830->availablePipes; n++) { - pipe = (pI830->configuredDevices >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK; + pipe = (pI830->operatingDevices >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK; pI830->pipeDisplaySize[n].x1 = pI830->pipeDisplaySize[n].y1 = 0; pI830->pipeDisplaySize[n].x2 = pI830->pipeDisplaySize[n].y2 = 4096; for (i = 0; i < NumKnownDisplayTypes; i++) { @@ -813,32 +912,15 @@ I830DetectDisplayDevice(ScrnInfoPtr pScrn) } } - pI830->configuredDevices = GetDisplayDevices(pScrn); - if (pI830->configuredDevices == -1) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Failed to detect active display devices\n"); - return FALSE; - } - /* Check for active devices connected to each display pipe. */ for (n = 0; n < pI830->availablePipes; n++) { - pipe = ((pI830->configuredDevices >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK); + pipe = ((pI830->operatingDevices >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK); if (pipe) { pI830->pipeEnabled[n] = TRUE; } } GetPipeSizes(pScrn); - PrintDisplayDeviceInfo(pScrn); - -#if 0 - /* A quick hack to change the set of enabled devices. */ - enabledDevices = PIPE_CRT_ACTIVE; - if (!SetDisplayDevices(pScrn, enabledDevices)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to switch to configured display devices\n"); - } -#endif return TRUE; } @@ -850,40 +932,51 @@ I830DetectMemory(ScrnInfoPtr pScrn) PCITAG bridge; CARD16 gmch_ctrl; int memsize = 0; + int range; bridge = pciTag(0, 0, 0); /* This is always the host bridge */ gmch_ctrl = pciReadWord(bridge, I830_GMCH_CTRL); - if (IS_I85X(pI830) || IS_I865G(pI830)) - { + /* We need to reduce the stolen size, by the GTT and the popup. + * The GTT varying according the the FbMapSize and the popup is 4KB */ + range = (pI830->FbMapSize / (1024*1024)) + 4; + + if (IS_I85X(pI830) || IS_I865G(pI830) || IS_I915G(pI830)) { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { case I855_GMCH_GMS_STOLEN_1M: - memsize = MB(1) - KB(132); + memsize = MB(1) - KB(range); break; case I855_GMCH_GMS_STOLEN_4M: - memsize = MB(4) - KB(132); + memsize = MB(4) - KB(range); break; case I855_GMCH_GMS_STOLEN_8M: - memsize = MB(8) - KB(132); + memsize = MB(8) - KB(range); break; case I855_GMCH_GMS_STOLEN_16M: - memsize = MB(16) - KB(132); + memsize = MB(16) - KB(range); break; case I855_GMCH_GMS_STOLEN_32M: - memsize = MB(32) - KB(132); + memsize = MB(32) - KB(range); + break; + case I915G_GMCH_GMS_STOLEN_48M: + if (IS_I915G(pI830)) + memsize = MB(48) - KB(range); + break; + case I915G_GMCH_GMS_STOLEN_64M: + if (IS_I915G(pI830)) + memsize = MB(64) - KB(range); break; } - } else - { + } else { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { case I830_GMCH_GMS_STOLEN_512: - memsize = KB(512) - KB(132); + memsize = KB(512) - KB(range); break; case I830_GMCH_GMS_STOLEN_1024: - memsize = MB(1) - KB(132); + memsize = MB(1) - KB(range); break; case I830_GMCH_GMS_STOLEN_8192: - memsize = MB(8) - KB(132); + memsize = MB(8) - KB(range); break; case I830_GMCH_GMS_LOCAL: memsize = 0; @@ -939,7 +1032,8 @@ I830MapMem(ScrnInfoPtr pScrn) if (!pI830->FbBase) return FALSE; - pI830->LpRing.virtual_start = pI830->FbBase + pI830->LpRing.mem.Start; + if (IsPrimary(pScrn)) + pI830->LpRing->virtual_start = pI830->FbBase + pI830->LpRing->mem.Start; return TRUE; } @@ -1079,22 +1173,25 @@ static CARD32 TweakMemorySize(ScrnInfoPtr pScrn, CARD32 newsize, Bool preinit) { #define SIZE 0x10000 -#define IDOFFSET (-23) +#define _855_IDOFFSET (-23) +#define _845_IDOFFSET (-19) + const char *MAGICstring = "Total time for VGA POST:"; const int len = strlen(MAGICstring); I830Ptr pI830 = I830PTR(pScrn); - char *position; + volatile char *position; char *biosAddr; CARD32 oldsize; CARD32 oldpermission; CARD32 ret = 0; int i,j = 0; + int reg = (IS_845G(pI830) || IS_I865G(pI830)) ? _845_DRAM_RW_CONTROL + : _855_DRAM_RW_CONTROL; + PCITAG tag =pciTag(0,0,0); if(!pI830->PciInfo - || !(pI830->PciInfo->chipType == PCI_CHIP_845_G - || pI830->PciInfo->chipType == PCI_CHIP_I855_GM - || pI830->PciInfo->chipType == PCI_CHIP_I865_G)) + || !(IS_845G(pI830) || IS_I85X(pI830) || IS_I865G(pI830))) return 0; if (!pI830->pVbe) @@ -1104,7 +1201,6 @@ TweakMemorySize(ScrnInfoPtr pScrn, CARD32 newsize, Bool preinit) pI830->pVbe->pInt10->BIOSseg << 4); if (!pI830->BIOSMemSizeLoc) { - if (!preinit) return 0; @@ -1120,30 +1216,33 @@ TweakMemorySize(ScrnInfoPtr pScrn, CARD32 newsize, Bool preinit) } if (j < len) return 0; - pI830->BIOSMemSizeLoc = (i - j + 1 + IDOFFSET); + pI830->BIOSMemSizeLoc = (i - j + 1 + (IS_845G(pI830) + ? _845_IDOFFSET : _855_IDOFFSET)); } - + position = biosAddr + pI830->BIOSMemSizeLoc; oldsize = *(CARD32 *)position; - ret = oldsize - (3 << 16); + ret = oldsize - 0x21000; + /* verify that register really contains current size */ - if (preinit && ((oldsize) >> 16) - 3 != pI830->vbeInfo->TotalMemory) + if (preinit && ((ret >> 16) != pI830->vbeInfo->TotalMemory)) return 0; - oldpermission = pciReadLong(tag, DRAM_RW_CONTROL); - pciWriteLong(tag, DRAM_RW_CONTROL, 0x33330000); + oldpermission = pciReadLong(tag, reg); + pciWriteLong(tag, reg, DRAM_WRITE | (oldpermission & 0xffff)); + + *(CARD32 *)position = newsize + 0x21000; - *(CARD32 *)position = newsize + (3 << 16); if (preinit) { /* reinitialize VBE for new size */ VBEFreeVBEInfo(pI830->vbeInfo); vbeFree(pI830->pVbe); pI830->pVbe = VBEInit(NULL, pI830->pEnt->index); pI830->vbeInfo = VBEGetVBEInfo(pI830->pVbe); - + /* verify that change was successful */ - if (pI830->vbeInfo->TotalMemory * 64 * 1024 != pI830->newBIOSMemSize) { + if (pI830->vbeInfo->TotalMemory != (newsize >> 16)){ ret = 0; *(CARD32 *)position = oldsize; } else { @@ -1154,7 +1253,7 @@ TweakMemorySize(ScrnInfoPtr pScrn, CARD32 newsize, Bool preinit) } } - pciWriteLong(tag, DRAM_RW_CONTROL, oldpermission); + pciWriteLong(tag, reg, oldpermission); return ret; } @@ -1250,7 +1349,7 @@ I830LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, DPRINTF(PFX, "I830LoadPalette: numColors: %d\n", numColors); pI830 = I830PTR(pScrn); - if (pI830->pipeEnabled[0]) { + if (pI830->pipe == 0) { /* It seems that an initial read is needed. */ temp = INREG(PALETTE_A); for (i = 0; i < numColors; i++) { @@ -1262,7 +1361,7 @@ I830LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, OUTREG(PALETTE_A + index * 4, val); } } - if (pI830->pipeEnabled[1]) { + if (pI830->pipe == 1) { /* It seems that an initial read is needed. */ temp = INREG(PALETTE_B); for (i = 0; i < numColors; i++) { @@ -1281,6 +1380,28 @@ PreInitCleanup(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); + if (IsPrimary(pScrn) && pI830->LpRing) { + xfree(pI830->LpRing); + pI830->LpRing = NULL; + } + if (IsPrimary(pScrn) && pI830->CursorMem) { + xfree(pI830->CursorMem); + pI830->CursorMem = NULL; + } + if (IsPrimary(pScrn) && pI830->CursorMemARGB) { + xfree(pI830->CursorMemARGB); + pI830->CursorMemARGB = NULL; + } + if (IsPrimary(pScrn) && pI830->OverlayMem) { + xfree(pI830->OverlayMem); + pI830->OverlayMem = NULL; + } + if (IsPrimary(pScrn) && pI830->overlayOn) { + xfree(pI830->overlayOn); + pI830->overlayOn = NULL; + } + if (!IsPrimary(pScrn) && pI830->entityPrivate) + pI830->entityPrivate->pScrn_2 = NULL; RestoreBIOSMemSize(pScrn); if (pI830->swfSaved) { OUTREG(SWF0, pI830->saveSWF0); @@ -1291,6 +1412,90 @@ PreInitCleanup(ScrnInfoPtr pScrn) I830BIOSFreeRec(pScrn); } +static int +GetBIOSPipe(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + int pipe; + + DPRINTF(PFX, "GetBIOSPipe:\n"); + + /* single pipe machines should always return Pipe A */ + if (pI830->availablePipes == 1) return 0; + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f1c; + pVbe->pInt10->bx = 0x100; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f1c, pVbe->pInt10->ax)) { + if (pI830->newPipeSwitch) { + pipe = ((pVbe->pInt10->bx & 0x0001)); + } else { + pipe = ((pVbe->pInt10->cx & 0x0100) >> 8); + } + return pipe; + } + + return -1; +} + +static Bool +SetBIOSPipe(ScrnInfoPtr pScrn, int pipe) +{ + I830Ptr pI830 = I830PTR(pScrn); + vbeInfoPtr pVbe = pI830->pVbe; + + DPRINTF(PFX, "SetBIOSPipe: pipe 0x%x\n", pipe); + + /* single pipe machines should always return TRUE */ + if (pI830->availablePipes == 1) return TRUE; + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f1c; + if (pI830->newPipeSwitch) { + pVbe->pInt10->bx = pipe; + pVbe->pInt10->cx = 0; + } else { + pVbe->pInt10->bx = 0x0; + pVbe->pInt10->cx = pipe << 8; + } + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f1c, pVbe->pInt10->ax)) + return TRUE; + + return FALSE; +} + +static Bool +SetPipeAccess(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + /* Don't try messing with the pipe, unless we're dual head */ + if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) { + if (!SetBIOSPipe(pScrn, pI830->pipe)) + return FALSE; + } + + return TRUE; +} + +static Bool +IsPrimary(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + + if (xf86IsEntityShared(pScrn->entityList[0])) { + if (pI830->init == 0) return TRUE; + else return FALSE; + } + + return TRUE; +} + static Bool I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) { @@ -1298,14 +1503,17 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) I830Ptr pI830; MessageType from; rgb defaultWeight = { 0, 0, 0 }; - vbeInfoPtr pVbe; EntityInfoPtr pEnt; + I830EntPtr pI830Ent = NULL; int mem, memsize; int flags24; int i, n; + char *s; pointer pDDCModule, pVBEModule; Bool enable; const char *chipname; + unsigned int ver; + char v[5]; if (pScrn->numEntities != 1) return FALSE; @@ -1332,7 +1540,6 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) return FALSE; xf86LoaderReqSymLists(I810vgahwSymbols, NULL); - /* Allocate a vgaHWRec */ if (!vgaHWGetHWRec(pScrn)) return FALSE; @@ -1352,10 +1559,17 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) pI830->PciTag = pciTag(pI830->PciInfo->bus, pI830->PciInfo->device, pI830->PciInfo->func); + /* Allocate an entity private if necessary */ + if (xf86IsEntityShared(pScrn->entityList[0])) { + pI830Ent = xf86GetEntityPrivate(pScrn->entityList[0], + I830EntityIndex)->ptr; + pI830->entityPrivate = pI830Ent; + } else + pI830->entityPrivate = NULL; + if (xf86RegisterResources(pI830->pEnt->index, 0, ResNone)) { PreInitCleanup(pScrn); return FALSE; - } pScrn->racMemFlags = RAC_FB | RAC_COLORMAP; @@ -1390,6 +1604,8 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) hwp = VGAHWPTR(pScrn); pI830->cpp = pScrn->bitsPerPixel / 8; + pI830->preinit = TRUE; + /* Process the options */ xf86CollectOptions(pScrn, NULL); if (!(pI830->Options = xalloc(sizeof(I830BIOSOptions)))) @@ -1440,6 +1656,9 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) case PCI_CHIP_I865_G: chipname = "865G"; break; + case PCI_CHIP_I915_G: + chipname = "915G"; + break; default: chipname = "unknown chipset"; break; @@ -1447,9 +1666,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Integrated Graphics Chipset: Intel(R) %s\n", chipname); - pVbe = pI830->pVbe; - - pI830->vbeInfo = VBEGetVBEInfo(pVbe); + pI830->vbeInfo = VBEGetVBEInfo(pI830->pVbe); /* Set the Chipset and ChipRev, allowing config file entries to override. */ if (pI830->pEnt->device->chipset && *pI830->pEnt->device->chipset) { @@ -1479,7 +1696,10 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) pI830->LinearAddr = pI830->pEnt->device->MemBase; from = X_CONFIG; } else { - if (pI830->PciInfo->memBase[1] != 0) { + if (IS_I915G(pI830)) { + pI830->LinearAddr = pI830->PciInfo->memBase[2] & 0xF0000000; + from = X_PROBED; + } else if (pI830->PciInfo->memBase[1] != 0) { /* XXX Check mask. */ pI830->LinearAddr = pI830->PciInfo->memBase[0] & 0xFF000000; from = X_PROBED; @@ -1498,7 +1718,10 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) pI830->MMIOAddr = pI830->pEnt->device->IOBase; from = X_CONFIG; } else { - if (pI830->PciInfo->memBase[1]) { + if (IS_I915G(pI830)) { + pI830->MMIOAddr = pI830->PciInfo->memBase[0] & 0xFFF80000; + from = X_PROBED; + } else if (pI830->PciInfo->memBase[1]) { pI830->MMIOAddr = pI830->PciInfo->memBase[1] & 0xFFF80000; from = X_PROBED; } else { @@ -1537,14 +1760,43 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { pI830->FbMapSize = 0x8000000; } else { - pI830->FbMapSize = 0x4000000; + pI830->FbMapSize = 0x4000000; /* 64MB - has this been tested ?? */ } + } else { + if (IS_I915G(pI830)) { + if (pI830->PciInfo->memBase[2] & 0x08000000) + pI830->FbMapSize = 0x8000000; /* 128MB aperture */ + else + pI830->FbMapSize = 0x10000000; /* 256MB aperture */ + } else + /* 128MB aperture for later chips */ + pI830->FbMapSize = 0x8000000; } - else { - /* 128MB aperture for later chips */ - pI830->FbMapSize = 0x8000000; + + + if (xf86IsEntityShared(pScrn->entityList[0])) { + if (xf86IsPrimInitDone(pScrn->entityList[0])) { + pI830->init = 1; + + if (!pI830Ent->pScrn_1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to setup second head due to primary head failure.\n"); + return FALSE; + } + + } else { + xf86SetPrimInitDone(pScrn->entityList[0]); + pI830->init = 0; + } } + if (IS_MOBILE(pI830) || IS_I915G(pI830)) + pI830->availablePipes = 2; + else + pI830->availablePipes = 1; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%d display pipe%s available.\n", + pI830->availablePipes, pI830->availablePipes > 1 ? "s" : ""); + /* * Get the pre-allocated (stolen) memory size. */ @@ -1562,8 +1814,14 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } /* Find the maximum amount of agpgart memory available. */ - mem = I830CheckAvailableMemory(pScrn); - pI830->StolenOnly = FALSE; + if (IsPrimary(pScrn)) { + mem = I830CheckAvailableMemory(pScrn); + pI830->StolenOnly = FALSE; + } else { + /* videoRam isn't used on the second head, but faked */ + mem = pI830->entityPrivate->pScrn_1->videoRam; + pI830->StolenOnly = TRUE; + } if (mem <= 0) { if (pI830->StolenMemory.Size <= 0) { @@ -1607,6 +1865,154 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } #endif + pI830->MonType1 = PIPE_NONE; + pI830->MonType2 = PIPE_NONE; + + if ((s = xf86GetOptValString(pI830->Options, OPTION_MONITOR_LAYOUT)) && + IsPrimary(pScrn)) { + char *Mon1; + char *Mon2; + char *sub; + + Mon1 = strtok(s, ","); + Mon2 = strtok(NULL, ","); + + if (Mon1) { + sub = strtok(Mon1, "+"); + do { + if (strcmp(sub, "NONE") == 0) + pI830->MonType1 |= PIPE_NONE; + else if (strcmp(sub, "CRT") == 0) + pI830->MonType1 |= PIPE_CRT; + else if (strcmp(sub, "TV") == 0) + pI830->MonType1 |= PIPE_TV; + else if (strcmp(sub, "DFP") == 0) + pI830->MonType1 |= PIPE_DFP; + else if (strcmp(sub, "LFP") == 0) + pI830->MonType1 |= PIPE_LFP; + else if (strcmp(sub, "CRT2") == 0) + pI830->MonType1 |= PIPE_CRT2; + else if (strcmp(sub, "TV2") == 0) + pI830->MonType1 |= PIPE_TV2; + else if (strcmp(sub, "DFP2") == 0) + pI830->MonType1 |= PIPE_DFP2; + else if (strcmp(sub, "LFP2") == 0) + pI830->MonType1 |= PIPE_LFP2; + else + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Invalid Monitor type specified for Pipe A\n"); + + sub = strtok(NULL, "+"); + } while (sub); + } + + if (Mon2) { + sub = strtok(Mon2, "+"); + do { + if (strcmp(sub, "NONE") == 0) + pI830->MonType2 |= PIPE_NONE; + else if (strcmp(sub, "CRT") == 0) + pI830->MonType2 |= PIPE_CRT; + else if (strcmp(sub, "TV") == 0) + pI830->MonType2 |= PIPE_TV; + else if (strcmp(sub, "DFP") == 0) + pI830->MonType2 |= PIPE_DFP; + else if (strcmp(sub, "LFP") == 0) + pI830->MonType2 |= PIPE_LFP; + else if (strcmp(sub, "CRT2") == 0) + pI830->MonType2 |= PIPE_CRT2; + else if (strcmp(sub, "TV2") == 0) + pI830->MonType2 |= PIPE_TV2; + else if (strcmp(sub, "DFP2") == 0) + pI830->MonType2 |= PIPE_DFP2; + else if (strcmp(sub, "LFP2") == 0) + pI830->MonType2 |= PIPE_LFP2; + else + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Invalid Monitor type specified for Pipe B\n"); + + sub = strtok(NULL, "+"); + } while (sub); + } + + if (pI830->availablePipes == 1 && pI830->MonType2 != PIPE_NONE) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Monitor 2 cannot be specified on single pipe devices\n"); + return FALSE; + } + + if (pI830->MonType1 == PIPE_NONE && pI830->MonType2 == PIPE_NONE) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Monitor 1 and 2 cannot be type NONE\n"); + return FALSE; + } + } + + if (xf86ReturnOptValBool(pI830->Options, OPTION_CLONE, FALSE)) { + if (pI830->availablePipes == 1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Can't enable Clone Mode because this is a single pipe device\n"); + PreInitCleanup(pScrn); + return FALSE; + } + if (pI830->entityPrivate) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Can't enable Clone Mode because second head is configured\n"); + PreInitCleanup(pScrn); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling Clone Mode\n"); + pI830->CloneRefresh = 60; /* default to 60Hz */ + if (xf86GetOptValInteger(pI830->Options, OPTION_CLONE_REFRESH, + &(pI830->CloneRefresh))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Clone Monitor Refresh Rate %d\n", + pI830->CloneRefresh); + } + if (pI830->CloneRefresh < 60 || pI830->CloneRefresh > 120) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad Clone Refresh Rate\n"); + PreInitCleanup(pScrn); + return FALSE; + } + pI830->Clone = TRUE; + } + + if ((pI830->entityPrivate && IsPrimary(pScrn)) || pI830->Clone) { + if ((!xf86GetOptValString(pI830->Options, OPTION_MONITOR_LAYOUT))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "You must have a MonitorLayout " + "defined for use in a DualHead or Clone setup.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + + if (pI830->MonType1 == PIPE_NONE || pI830->MonType2 == PIPE_NONE) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Monitor 1 or Monitor 2 " + "cannot be type NONE in Dual or Clone setup.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + } + + /* + * Let's setup the mobile systems to check the lid status + */ + if (IS_MOBILE(pI830)) { + pI830->checkLid = TRUE; + + if (!xf86ReturnOptValBool(pI830->Options, OPTION_CHECKLID, TRUE)) { + pI830->checkLid = FALSE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Checking Lid status disabled\n"); + } else + if (pI830->entityPrivate && !IsPrimary(pScrn) && + !I830PTR(pI830->entityPrivate->pScrn_1)->checkLid) { + /* If checklid is off, on the primary head, then + * turn it off on the secondary*/ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Checking Lid status disabled\n"); + pI830->checkLid = FALSE; + } else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Checking Lid status enabled\n"); + } else + pI830->checkLid = FALSE; + /* * The "VideoRam" config file parameter specifies the total amount of * memory that will be used/allocated. When agpgart support isn't @@ -1620,6 +2026,10 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) * amount is higher, default to it rounded up to the nearest MB. This * guarantees that by default there will be at least some run-time * space for things that need a physical address. + * But, we double the amounts when dual head is enabled, and therefore + * for 2D-only we use 16384KB, and 3D we use 65536KB. The VideoRAM + * for the second head is never used, as the primary head does the + * allocation. */ if (!pI830->pEnt->device->videoRam) { from = X_DEFAULT; @@ -1629,6 +2039,14 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) else #endif pScrn->videoRam = I830_DEFAULT_VIDEOMEM_2D; + + if (xf86IsEntityShared(pScrn->entityList[0])) { + if (IsPrimary(pScrn)) + pScrn->videoRam *= 2; + else + pScrn->videoRam = I830_MAXIMUM_VBIOS_MEM; + } + if (pI830->StolenMemory.Size / 1024 > pScrn->videoRam) pScrn->videoRam = ROUND_TO(pI830->StolenMemory.Size / 1024, 1024); } else { @@ -1679,7 +2097,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) */ /* Try to keep HW cursor and Overlay amounts separate from this. */ - int reserve = (HWCURSOR_SIZE + OVERLAY_SIZE) / 1024; + int reserve = (HWCURSOR_SIZE + HWCURSOR_SIZE_ARGB + OVERLAY_SIZE) / 1024; if (pScrn->videoRam - reserve >= I830_MAXIMUM_VBIOS_MEM) pI830->newBIOSMemSize = KB(I830_MAXIMUM_VBIOS_MEM); @@ -1698,29 +2116,29 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) VBEFreeVBEInfo(pI830->vbeInfo); vbeFree(pI830->pVbe); pI830->pVbe = VBEInit(NULL, pI830->pEnt->index); - pVbe = pI830->pVbe; - pI830->vbeInfo = VBEGetVBEInfo(pVbe); + pI830->vbeInfo = VBEGetVBEInfo(pI830->pVbe); pI830->BIOSMemorySize = KB(pI830->vbeInfo->TotalMemory * 64); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS now sees %ld kB VideoRAM\n", pI830->BIOSMemorySize / 1024); - } else if ((pI830->saveBIOSMemSize - = TweakMemorySize(pScrn, pI830->newBIOSMemSize, TRUE)) != 0) - pI830->overrideBIOSMemSize = TRUE; - else { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "BIOS view of memory size can't be changed " - "(this is not an error).\n"); + } else if ((pI830->saveBIOSMemSize + = TweakMemorySize(pScrn, pI830->newBIOSMemSize,TRUE)) != 0) + pI830->overrideBIOSMemSize = TRUE; + else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "BIOS view of memory size can't be changed " + "(this is not an error).\n"); } } } - pVbe = pI830->pVbe; - - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Pre-allocated VideoRAM: %ld kByte\n", + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "Pre-allocated VideoRAM: %ld kByte\n", pI830->StolenMemory.Size / 1024); - xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n", pScrn->videoRam); + xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n", + pScrn->videoRam); + pI830->TotalVideoRam = KB(pScrn->videoRam); /* @@ -1771,20 +2189,204 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } #endif + /* + * If the driver can do gamma correction, it should call xf86SetGamma() here. + */ + + { + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrn, zeros)) { + PreInitCleanup(pScrn); + return FALSE; + } + } + + GetBIOSVersion(pScrn, &ver); + + v[0] = (ver & 0xff000000) >> 24; + v[1] = (ver & 0x00ff0000) >> 16; + v[2] = (ver & 0x0000ff00) >> 8; + v[3] = (ver & 0x000000ff) >> 0; + v[4] = 0; + + pI830->bios_version = atoi(v); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS Build: %d\n",pI830->bios_version); + + /* BIOS build 3062 changed the pipe switching functionality */ + if (pI830->availablePipes == 2 && pI830->bios_version >= 3062) { + pI830->newPipeSwitch = TRUE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using new Pipe switch code\n"); + } else + pI830->newPipeSwitch = FALSE; + + pI830->devicePresence = FALSE; + from = X_DEFAULT; + if (xf86ReturnOptValBool(pI830->Options, OPTION_DEVICE_PRESENCE, FALSE)) { + pI830->devicePresence = TRUE; + from = X_CONFIG; + } + xf86DrvMsg(pScrn->scrnIndex, from, "Device Presence: %s.\n", + pI830->devicePresence ? "enabled" : "disabled"); + + /* This performs an active detect of the currently attached monitors + * or, at least it's meant to..... alas it doesn't seem to always work. + */ + if (pI830->devicePresence) { + int req, att, enc; + GetDevicePresence(pScrn, &req, &att, &enc); + for (i = 0; i < NumDisplayTypes; i++) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Display Presence: %s: attached: %s, encoder: %s\n", + displayDevices[i], + BOOLTOSTRING(((1<<i) & att)>>i), + BOOLTOSTRING(((1<<i) & enc)>>i)); + } + } + + /* Save old configuration of detected devices */ + pI830->savedDevices = GetDisplayDevices(pScrn); + + if (IsPrimary(pScrn)) { + pI830->pipe = GetBIOSPipe(pScrn); + + if (xf86ReturnOptValBool(pI830->Options, OPTION_FLIP_PRIMARY, FALSE)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Primary flipping enabled\n"); + pI830->pipe = !pI830->pipe; + } + + /* If the monitors aren't setup, read from the current config */ + if (pI830->MonType1 == PIPE_NONE) + pI830->MonType1 = pI830->savedDevices & 0xff; + if (pI830->MonType2 == PIPE_NONE) + pI830->MonType2 = (pI830->savedDevices & 0xff00) >> 8; + + pI830->operatingDevices = (pI830->MonType2 << 8) | pI830->MonType1; + + if (!xf86IsEntityShared(pScrn->entityList[0]) && !pI830->Clone) { + /* If we're not dual head or clone, turn off the second head, + * if monitorlayout is also specified. */ + + if (pI830->pipe == 0) + pI830->operatingDevices = pI830->MonType1; + else + pI830->operatingDevices = pI830->MonType2 << 8; + + if (pI830->operatingDevices & 0xFF00) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Primary Pipe is %s, switching off second monitor (0x%x)\n", + pI830->pipe ? "B" : "A", pI830->operatingDevices); + } + } else { + I830Ptr pI8301 = I830PTR(pI830Ent->pScrn_1); + pI830->operatingDevices = pI8301->operatingDevices; + } + + /* Buggy BIOS 3066 is known to cause this, so turn this off */ + if (pI830->bios_version == 3066) { + pI830->displayInfo = FALSE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Detected Broken Video BIOS, turning off displayInfo.\n"); + } else + pI830->displayInfo = TRUE; + from = X_DEFAULT; + if (!xf86ReturnOptValBool(pI830->Options, OPTION_DISPLAY_INFO, TRUE)) { + pI830->displayInfo = FALSE; + from = X_CONFIG; + } + if (xf86ReturnOptValBool(pI830->Options, OPTION_DISPLAY_INFO, FALSE)) { + pI830->displayInfo = TRUE; + from = X_CONFIG; + } + xf86DrvMsg(pScrn->scrnIndex, from, "Display Info: %s.\n", + pI830->displayInfo ? "enabled" : "disabled"); + + if (!I830DetectDisplayDevice(pScrn)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Couldn't detect display devices.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + + if (!SetDisplayDevices(pScrn, pI830->operatingDevices)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to switch to monitor configuration (0x%x)\n", + pI830->operatingDevices); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Please check the devices specified in your MonitorLayout\n"); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "is configured correctly.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + + PrintDisplayDeviceInfo(pScrn); + + if (xf86IsEntityShared(pScrn->entityList[0])) { + if (!IsPrimary(pScrn)) { + I830Ptr pI8301 = I830PTR(pI830Ent->pScrn_1); + + pI830Ent->pScrn_2 = pScrn; + pI830->pipe = !pI8301->pipe; + + /* This could be made to work with a little more fiddling */ + pI830->directRenderingDisabled = TRUE; + + xf86DrvMsg(pScrn->scrnIndex, from, "Secondary head is using Pipe %s\n", + pI830->pipe ? "B" : "A"); + } else { + pI830Ent->pScrn_1 = pScrn; + pI830Ent->pScrn_2 = NULL; + + xf86DrvMsg(pScrn->scrnIndex, from, "Primary head is using Pipe %s\n", + pI830->pipe ? "B" : "A"); + } + } else { + xf86DrvMsg(pScrn->scrnIndex, from, "Display is using Pipe %s\n", + pI830->pipe ? "B" : "A"); + } + + /* Alloc our pointers for the primary head */ + if (IsPrimary(pScrn)) { + pI830->LpRing = xalloc(sizeof(I830RingBuffer)); + pI830->CursorMem = xalloc(sizeof(I830MemRange)); + pI830->CursorMemARGB = xalloc(sizeof(I830MemRange)); + pI830->OverlayMem = xalloc(sizeof(I830MemRange)); + pI830->overlayOn = xalloc(sizeof(Bool)); + if (!pI830->LpRing || !pI830->CursorMem || !pI830->CursorMemARGB || + !pI830->OverlayMem || !pI830->overlayOn) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Could not allocate primary data structures.\n"); + PreInitCleanup(pScrn); + return FALSE; + } + *pI830->overlayOn = FALSE; + if (pI830->entityPrivate) + pI830->entityPrivate->XvInUse = -1; + } + /* Check if the HW cursor needs physical address. */ - if (IS_MOBILE(pI830)) + if (IS_MOBILE(pI830) || IS_I915G(pI830)) pI830->CursorNeedsPhysical = TRUE; else pI830->CursorNeedsPhysical = FALSE; /* Force ring buffer to be in low memory for the 845G and later. */ - if (IS_845G(pI830) || IS_I85X(pI830) || IS_I865G(pI830)) + if (IS_845G(pI830) || IS_I85X(pI830) || IS_I865G(pI830) || IS_I915G(pI830)) pI830->NeedRingBufferLow = TRUE; /* * XXX If we knew the pre-initialised GTT format for certain, we could * probably figure out the physical address even in the StolenOnly case. */ + if (!IsPrimary(pScrn)) { + I830Ptr pI8301 = I830PTR(pI830Ent->pScrn_1); + if (!pI8301->SWCursor) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "Using HW Cursor because it's enabled on primary head.\n"); + pI830->SWCursor = FALSE; + } + } else if (pI830->StolenOnly && pI830->CursorNeedsPhysical && !pI830->SWCursor) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "HW Cursor disabled because it needs agpgart memory.\n"); @@ -1795,8 +2397,10 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) * Reduce the maximum videoram available for video modes by the ring buffer, * minimum scratch space and HW cursor amounts. */ - if (!pI830->SWCursor) + if (!pI830->SWCursor) { pScrn->videoRam -= (HWCURSOR_SIZE / 1024); + pScrn->videoRam -= (HWCURSOR_SIZE_ARGB / 1024); + } if (!pI830->XvDisabled) pScrn->videoRam -= (OVERLAY_SIZE / 1024); if (!pI830->noAccel) { @@ -1807,46 +2411,13 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Maximum frambuffer space: %d kByte\n", pScrn->videoRam); - /* - * If the driver can do gamma correction, it should call xf86SetGamma() here. - */ - - { - Gamma zeros = { 0.0, 0.0, 0.0 }; - - if (!xf86SetGamma(pScrn, zeros)) - return FALSE; - } - - if (IS_MOBILE(pI830)) - pI830->availablePipes = 2; - else - pI830->availablePipes = 1; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%d display pipe%s available.\n", - pI830->availablePipes, pI830->availablePipes > 1 ? "s" : ""); - - pI830->displayInfo = TRUE; - from = X_DEFAULT; - if (!xf86ReturnOptValBool(pI830->Options, OPTION_DISPLAY_INFO, TRUE)) { - from = X_CONFIG; - pI830->displayInfo = FALSE; - } - xf86DrvMsg(pScrn->scrnIndex, from, "Display Info: %s.\n", - pI830->displayInfo ? "enabled" : "disabled"); - - if (!I830DetectDisplayDevice(pScrn)) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Couldn't detect display devices.\n"); - PreInitCleanup(pScrn); - return FALSE; - } - + SetPipeAccess(pScrn); if ((pDDCModule = xf86LoadSubModule(pScrn, "ddc")) == NULL) { PreInitCleanup(pScrn); return FALSE; } - if ((pI830->vesa->monitor = vbeDoEDID(pVbe, pDDCModule)) != NULL) { + if ((pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule)) != NULL) { xf86PrintEDID(pI830->vesa->monitor); } if ((pScrn->monitor->DDC = pI830->vesa->monitor) != NULL) @@ -1875,22 +2446,42 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } #endif - for (i = 0; i < pI830->availablePipes; i++) { + pI830->useExtendedRefresh = FALSE; + + if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) { int pipe = - (pI830->configuredDevices >> PIPE_SHIFT(i)) & PIPE_ACTIVE_MASK; + (pI830->operatingDevices >> PIPE_SHIFT(pI830->pipe)) & PIPE_ACTIVE_MASK; if (pipe & ~PIPE_CRT_ACTIVE) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "A non-CRT device is attached to pipe %c.\n" "\tNo refresh rate overrides will be attempted.\n", - PIPE_NAME(i)); + PIPE_NAME(pI830->pipe)); pI830->vesa->useDefaultRefresh = TRUE; } /* * Some desktop platforms might not have 0x5f05, so useExtendedRefresh * would need to be set to FALSE for those cases. */ - if (!pI830->vesa->useDefaultRefresh) + if (!pI830->vesa->useDefaultRefresh) pI830->useExtendedRefresh = TRUE; + } else { + for (i = 0; i < pI830->availablePipes; i++) { + int pipe = + (pI830->operatingDevices >> PIPE_SHIFT(i)) & PIPE_ACTIVE_MASK; + if (pipe & ~PIPE_CRT_ACTIVE) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "A non-CRT device is attached to pipe %c.\n" + "\tNo refresh rate overrides will be attempted.\n", + PIPE_NAME(i)); + pI830->vesa->useDefaultRefresh = TRUE; + } + /* + * Some desktop platforms might not have 0x5f05, so useExtendedRefresh + * would need to be set to FALSE for those cases. + */ + if (!pI830->vesa->useDefaultRefresh) + pI830->useExtendedRefresh = TRUE; + } } if (pI830->useExtendedRefresh) { @@ -1899,18 +2490,6 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } /* - * Calling 0x5f64 can reset the refresh rate, so only do this when - * using 0x5f05, or when not overriding the default refresh rate. - * Also, 0x5f64 doesn't work correctly in i830 platforms. - */ - pI830->enableDisplays = !IS_I830(pI830) && pI830->useExtendedRefresh; - - if (pI830->enableDisplays) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Will use BIOS call 0x5f64 to enable displays.\n"); - } - - /* * Limit videoram available for mode selection to what the video * BIOS can see. */ @@ -1926,7 +2505,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) * functions. For that reason it's important to set only * V_MODETYPE_VGA in the flags for VBEGetModePool(). */ - pScrn->modePool = VBEGetModePool(pScrn, pVbe, pI830->vbeInfo, + pScrn->modePool = VBEGetModePool(pScrn, pI830->pVbe, pI830->vbeInfo, V_MODETYPE_VGA); if (!pScrn->modePool) { @@ -1936,6 +2515,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) return FALSE; } + SetPipeAccess(pScrn); VBESetModeNames(pScrn->modePool); /* @@ -1947,6 +2527,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) /* XXX Need to get relevant modes and virtual parameters. */ /* Do the mode validation without regard to special scanline pitches. */ + SetPipeAccess(pScrn); n = VBEValidateModes(pScrn, NULL, pScrn->display->modes, NULL, NULL, 0, MAX_DISPLAY_PITCH, 1, 0, MAX_DISPLAY_HEIGHT, @@ -1968,17 +2549,17 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) PreInitCleanup(pScrn); return FALSE; } - #ifndef USE_PITCHES #define USE_PITCHES 1 #endif + pI830->disableTiling = FALSE; /* * If DRI is potentially usable, check if there is enough memory available * for it, and if there's also enough to allow tiling to be enabled. */ #if defined(XF86DRI) - if (!pI830->directRenderingDisabled) { + if (IsPrimary(pScrn) && !pI830->directRenderingDisabled) { int savedDisplayWidth = pScrn->displayWidth; int memNeeded = 0; /* Good pitches to allow tiling. Don't care about pitches < 256. */ @@ -2088,6 +2669,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } #endif + SetPipeAccess(pScrn); VBEPrintModes(pScrn); if (!pI830->vesa->useDefaultRefresh) { @@ -2098,7 +2680,8 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) * This only works for VBE 3.0 and later. Also, we only do this * if there are no non-CRT devices attached. */ - VBESetModeParameters(pScrn, pVbe); + SetPipeAccess(pScrn); + VBESetModeParameters(pScrn, pI830->pVbe); } /* PreInit shouldn't leave any state changes, so restore this. */ @@ -2109,7 +2692,6 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) OUTREG(SWF0, pI830->saveSWF0); OUTREG(SWF4, pI830->saveSWF4); } - I830UnmapMMIO(pScrn); /* Set display resolution */ xf86SetDpi(pScrn, 0, 0); @@ -2138,13 +2720,20 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) xf86LoaderReqSymLists(I810ramdacSymbols, NULL); } + if (!SetDisplayDevices(pScrn, pI830->savedDevices)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to switch to saved display devices, continuing.\n"); + } + + I830UnmapMMIO(pScrn); + /* We won't be using the VGA access after the probe. */ I830SetMMIOAccess(pI830); xf86SetOperatingState(resVgaIo, pI830->pEnt->index, ResUnusedOpr); xf86SetOperatingState(resVgaMem, pI830->pEnt->index, ResDisableOpr); VBEFreeVBEInfo(pI830->vbeInfo); - vbeFree(pVbe); + vbeFree(pI830->pVbe); /* Use the VBE mode restore workaround by default. */ pI830->vbeRestoreWorkaround = TRUE; @@ -2174,6 +2763,8 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } #endif + pI830->preinit = FALSE; + return TRUE; } @@ -2188,6 +2779,8 @@ CheckInheritedState(ScrnInfoPtr pScrn) int errors = 0, fatal = 0; unsigned long temp, head, tail; + if (!IsPrimary(pScrn)) return TRUE; + /* Check first for page table errors */ temp = INREG(PGE_ERR); if (temp != 0) { @@ -2214,6 +2807,7 @@ CheckInheritedState(ScrnInfoPtr pScrn) "ring buffer not flushed\n", head, tail); errors++; } + #if 0 if (errors) I830PrintErrorState(pScrn); @@ -2240,6 +2834,11 @@ ResetState(ScrnInfoPtr pScrn, Bool flush) DPRINTF(PFX, "ResetState: flush is %s\n", BOOLTOSTRING(flush)); + if (!IsPrimary(pScrn)) return; + + if (pI830->entityPrivate) + pI830->entityPrivate->RingRunning = 0; + /* Reset the fence registers to 0 */ for (i = 0; i < 8; i++) OUTREG(FENCE + i * 4, 0); @@ -2270,6 +2869,8 @@ SetFenceRegs(ScrnInfoPtr pScrn) DPRINTF(PFX, "SetFenceRegs\n"); + if (!IsPrimary(pScrn)) return; + for (i = 0; i < 8; i++) { OUTREG(FENCE + i * 4, pI830->ModeReg.Fence[i]); if (I810_DEBUG & DEBUG_VERBOSE_VGA) @@ -2288,29 +2889,34 @@ SetRingRegs(ScrnInfoPtr pScrn) if (pI830->noAccel) return; + if (!IsPrimary(pScrn)) return; + + if (pI830->entityPrivate) + pI830->entityPrivate->RingRunning = 1; + OUTREG(LP_RING + RING_LEN, 0); OUTREG(LP_RING + RING_TAIL, 0); OUTREG(LP_RING + RING_HEAD, 0); - if ((pI830->LpRing.mem.Start & I830_RING_START_MASK) != - pI830->LpRing.mem.Start) { + if ((pI830->LpRing->mem.Start & I830_RING_START_MASK) != + pI830->LpRing->mem.Start) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "I830SetRingRegs: Ring buffer start (%lx) violates its " - "mask (%x)\n", pI830->LpRing.mem.Start, I830_RING_START_MASK); + "mask (%x)\n", pI830->LpRing->mem.Start, I830_RING_START_MASK); } /* Don't care about the old value. Reserved bits must be zero anyway. */ - itemp = pI830->LpRing.mem.Start & I830_RING_START_MASK; + itemp = pI830->LpRing->mem.Start & I830_RING_START_MASK; OUTREG(LP_RING + RING_START, itemp); - if (((pI830->LpRing.mem.Size - 4096) & I830_RING_NR_PAGES) != - pI830->LpRing.mem.Size - 4096) { + if (((pI830->LpRing->mem.Size - 4096) & I830_RING_NR_PAGES) != + pI830->LpRing->mem.Size - 4096) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "I830SetRingRegs: Ring buffer size - 4096 (%lx) violates its " - "mask (%x)\n", pI830->LpRing.mem.Size - 4096, + "mask (%x)\n", pI830->LpRing->mem.Size - 4096, I830_RING_NR_PAGES); } /* Don't care about the old value. Reserved bits must be zero anyway. */ - itemp = (pI830->LpRing.mem.Size - 4096) & I830_RING_NR_PAGES; + itemp = (pI830->LpRing->mem.Size - 4096) & I830_RING_NR_PAGES; itemp |= (RING_NO_REPORT | RING_VALID); OUTREG(LP_RING + RING_LEN, itemp); I830RefreshRing(pScrn); @@ -2346,7 +2952,10 @@ SaveHWState(ScrnInfoPtr pScrn) DPRINTF(PFX, "SaveHWState\n"); + SetPipeAccess(pScrn); + pVesa = pI830->vesa; + /* Make sure we save at least this information in case of failure. */ VBEGetVBEMode(pVbe, &pVesa->stateMode); modeInfo = VBEGetModeInfo(pVbe, pVesa->stateMode); @@ -2397,6 +3006,8 @@ SaveHWState(ScrnInfoPtr pScrn) return FALSE; } + VBEGetDisplayStart(pVbe, &pVesa->x, &pVesa->y); + return TRUE; } @@ -2478,6 +3089,8 @@ RestoreHWState(ScrnInfoPtr pScrn) if (pVesa->savedPal) VBESetGetPaletteData(pVbe, TRUE, 0, 256, pVesa->savedPal, FALSE, TRUE); + VBESetDisplayStart(pVbe, pVesa->x, pVesa->y, TRUE); + vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS); vgaHWLock(hwp); return TRUE; @@ -2487,12 +3100,92 @@ RestoreHWState(ScrnInfoPtr pScrn) #define USE_VBE 1 #endif +static void I830SetCloneVBERefresh(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock * block, int refresh) +{ + I830Ptr pI830 = I830PTR(pScrn); + DisplayModePtr p = NULL; + int RefreshRate; + int clock; + + /* Search for our mode and get a refresh to match */ + for (p = pScrn->monitor->Modes; p != NULL; p = p->next) { + if ((p->HDisplay != pI830->CloneHDisplay) || + (p->VDisplay != pI830->CloneVDisplay) || + (p->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2))) + continue; + RefreshRate = ((double)(p->Clock * 1000) / + (double)(p->HTotal * p->VTotal)) * 100; + /* we could probably do better here that 2Hz boundaries */ + if (RefreshRate > (refresh - 200) && RefreshRate < (refresh + 200)) { + block->HorizontalTotal = p->HTotal; + block->HorizontalSyncStart = p->HSyncStart; + block->HorizontalSyncEnd = p->HSyncEnd; + block->VerticalTotal = p->VTotal; + block->VerticalSyncStart = p->VSyncStart; + block->VerticalSyncEnd = p->VSyncEnd; + block->Flags = ((p->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) | + ((p->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0); + block->PixelClock = p->Clock * 1000; + /* XXX May not have this. */ + clock = VBEGetPixelClock(pI830->pVbe, mode, block->PixelClock); +#ifdef DEBUG + ErrorF("Setting clock %.2fMHz, closest is %.2fMHz\n", + (double)data->block->PixelClock / 1000000.0, + (double)clock / 1000000.0); +#endif + if (clock) + block->PixelClock = clock; + block->RefreshRate = ((double)(block->PixelClock) / + (double)(p->HTotal * p->VTotal)) * 100; + return; + } + } +} + static Bool I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock * block) { I830Ptr pI830 = I830PTR(pScrn); DPRINTF(PFX, "Setting mode 0x%.8x\n", mode); + + if (pI830->Clone && !pI830->preinit) { + VbeCRTCInfoBlock newblock; + int Mon; + + if (!pI830->pipe) + Mon = pI830->MonType2; + else + Mon = pI830->MonType1; + + SetBIOSPipe(pScrn, !pI830->pipe); + + /* The reason for this code is if we've not got a CRT on this pipe, then + * make sure we're using a 60Hz refresh */ + if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh && + (mode & (1 << 11)) && block) { + /* we'll call 5F05 to set the refresh later.... */ + if (Mon != PIPE_CRT) + VBESetVBEMode(pI830->pVbe, mode, NULL); + else + VBESetVBEMode(pI830->pVbe, mode, block); + } else { + if (Mon != PIPE_CRT) + /* Set clone head to 60Hz because we ain't got a CRT on it */ + I830SetCloneVBERefresh(pScrn, mode, &newblock, 6000); + else + /* Set clone head to specified clone refresh rate */ + I830SetCloneVBERefresh(pScrn, mode, &newblock, pI830->CloneRefresh * 100); + if (newblock.RefreshRate == 0) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to setup clone head mode resolution and refresh.\n"); + else + VBESetVBEMode(pI830->pVbe, mode, &newblock); + } + } + + SetPipeAccess(pScrn); + #if USE_VBE return VBESetVBEMode(pI830->pVbe, mode, block); #else @@ -2516,7 +3209,7 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) { I830Ptr pI830 = I830PTR(pScrn); vbeInfoPtr pVbe = pI830->pVbe; - VbeModeInfoData *data; + VbeModeInfoData *data = (VbeModeInfoData *) pMode->Private; int mode, i; CARD32 planeA, planeB, temp; int refresh = 60; @@ -2526,8 +3219,6 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) DPRINTF(PFX, "I830VESASetMode\n"); - data = (VbeModeInfoData *) pMode->Private; - /* Always Enable Linear Addressing */ mode = data->mode | (1 << 15) | (1 << 14); @@ -2539,6 +3230,26 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) } #endif + /* + * Do this early to find out if we can support it or not.... + * Test if the extendedRefresh BIOS function is supported. + */ + if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh && + (mode & (1 << 11)) && data && data->data && data->block) { + SetPipeAccess(pScrn); + if (!SetRefreshRate(pScrn, mode, 60)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "BIOS call 0x5f05 not supported, " + "setting refresh with VBE 3 method.\n"); + pI830->useExtendedRefresh = FALSE; + } + } + + if (pI830->Clone) { + pI830->CloneHDisplay = pMode->HDisplay; + pI830->CloneVDisplay = pMode->VDisplay; + } + #ifndef MODESWITCH_RESET_STATE #define MODESWITCH_RESET_STATE 0 #endif @@ -2568,57 +3279,62 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) } /* - * Test if the extendedRefresh BIOS function is supported. - */ - if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh && - (mode & (1 << 11)) && data && data->data && data->block) { - if (!SetRefreshRate(pScrn, mode, 60)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "BIOS call 0x5f05 not supported, " - "setting refresh with VBE 3 method.\n"); - pI830->useExtendedRefresh = FALSE; - pI830->enableDisplays = FALSE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Not using BIOS call 0x5f64 to enable displays.\n"); - } - } - - /* * The BIOS may not set a scanline pitch that would require more video * memory than it's aware of. We check for this later, and set it * explicitly if necessary. */ - if (data->data->XResolution != pScrn->displayWidth) + if (data->data->XResolution != pScrn->displayWidth) { + if (pI830->Clone) { + SetBIOSPipe(pScrn, !pI830->pipe); + VBESetLogicalScanline(pVbe, pScrn->displayWidth); + } + SetPipeAccess(pScrn); VBESetLogicalScanline(pVbe, pScrn->displayWidth); + } - if (pScrn->bitsPerPixel >= 8 && pI830->vbeInfo->Capabilities[0] & 0x01) + if (pScrn->bitsPerPixel >= 8 && pI830->vbeInfo->Capabilities[0] & 0x01) { + if (pI830->Clone) { + SetBIOSPipe(pScrn, !pI830->pipe); + VBESetGetDACPaletteFormat(pVbe, 8); + } + SetPipeAccess(pScrn); VBESetGetDACPaletteFormat(pVbe, 8); + } /* - * XXX This location of this isn't correct. - * - * Turn on the configured displays. This has the effect of resetting - * the default refresh rates to values that the configured displays - * can handle. This seems to be the safest way to make sure that this - * happens. When it's safe to set higher values, we do that after this. - * - * Note: When a DFP is connected to an 830, this causes the mode setting - * to be trashed. So, we don't do it on the 830. - * - * XXX Need to test an 830 with a LFP. + * When it's OK to set better than default refresh rates, set them here. */ - if (pI830->enableDisplays) { - if (!SetDisplayDevices(pScrn, pI830->configuredDevices)) { + if (pI830->Clone) { + int Mon; + if (!pI830->pipe) + Mon = pI830->MonType2; + else + Mon = pI830->MonType1; + SetBIOSPipe(pScrn, !pI830->pipe); + if (pI830->CloneRefresh && (Mon == PIPE_CRT)) { + if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh && + (mode & (1 << 11)) && data && data->data && data->block) { + refresh = SetRefreshRate(pScrn, mode, pI830->CloneRefresh); + if (!refresh) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to set refresh rate to %dHz on Clone head.\n", + pI830->CloneRefresh); + else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Set refresh rate to %dHz on Clone head.\n", + pI830->CloneRefresh); + } else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Will use VBE3 method to set refresh on Clone head.\n"); + } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to switch to configured display devices\n"); + "Not attempting to override default refresh on non-CRT clone head\n"); } } - /* - * When it's OK to set better than default refresh rates, set them here. - */ if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh && (mode & (1 << 11)) && data && data->data && data->block) { + SetPipeAccess(pScrn); refresh = SetRefreshRate(pScrn, mode, data->block->RefreshRate / 100); if (!refresh) { refresh = 60; @@ -2628,7 +3344,6 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) } } - /* XXX Fix plane A with pipe A, and plane B with pipe B. */ planeA = INREG(DSPACNTR); planeB = INREG(DSPBCNTR); @@ -2636,10 +3351,20 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) pI830->planeEnabled[0] = ((planeA & DISPLAY_PLANE_ENABLE) != 0); pI830->planeEnabled[1] = ((planeB & DISPLAY_PLANE_ENABLE) != 0); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane A is %s.\n", - pI830->planeEnabled[0] ? "enabled" : "disabled"); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane B is %s.\n", - pI830->planeEnabled[1] ? "enabled" : "disabled"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane A is %s and connected to %s.\n", + pI830->planeEnabled[0] ? "enabled" : "disabled", + planeA & DISPPLANE_SEL_PIPE_MASK ? "Pipe B" : "Pipe A"); + if (pI830->availablePipes == 2) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane B is %s and connected to %s.\n", + pI830->planeEnabled[1] ? "enabled" : "disabled", + planeB & DISPPLANE_SEL_PIPE_MASK ? "Pipe B" : "Pipe A"); + + if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) { + pI830->planeEnabled[0] = 1; + pI830->pipeEnabled[0] = 1; + pI830->planeEnabled[1] = 1; + pI830->pipeEnabled[1] = 1; + } /* * Sometimes it seems that no display planes are enabled at this point. @@ -2647,7 +3372,7 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) * For others choose plane A. */ if (!pI830->planeEnabled[0] && !pI830->planeEnabled[1]) { - if (IS_MOBILE(pI830)) { + if (pI830->availablePipes == 2) { if ((pI830->pipeEnabled[0] && ((planeA & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_A)) || (pI830->pipeEnabled[1] && @@ -2663,24 +3388,38 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) } else { pI830->planeEnabled[0] = TRUE; } - if (pI830->planeEnabled[0]) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling plane A.\n"); - planeA |= DISPLAY_PLANE_ENABLE; - OUTREG(DSPACNTR, planeA); - /* flush the change. */ - temp = INREG(DSPABASE); - OUTREG(DSPABASE, temp); - } - if (pI830->planeEnabled[1]) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling plane B.\n"); - planeB |= DISPLAY_PLANE_ENABLE; - OUTREG(DSPBCNTR, planeB); - /* flush the change. */ - temp = INREG(DSPBADDR); - OUTREG(DSPBADDR, temp); - } + } + if (pI830->planeEnabled[0]) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling plane A.\n"); + planeA |= DISPLAY_PLANE_ENABLE; + planeA &= ~DISPPLANE_SEL_PIPE_MASK; + planeA |= DISPPLANE_SEL_PIPE_A; + OUTREG(DSPACNTR, planeA); + /* flush the change. */ + temp = INREG(DSPABASE); + OUTREG(DSPABASE, temp); + } + if (pI830->planeEnabled[1]) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling plane B.\n"); + planeB |= DISPLAY_PLANE_ENABLE; + planeB &= ~DISPPLANE_SEL_PIPE_MASK; + planeB |= DISPPLANE_SEL_PIPE_B; + OUTREG(DSPBCNTR, planeB); + /* flush the change. */ + temp = INREG(DSPBADDR); + OUTREG(DSPBADDR, temp); } + planeA = INREG(DSPACNTR); + planeB = INREG(DSPBCNTR); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane A is now %s and connected to %s.\n", + pI830->planeEnabled[0] ? "enabled" : "disabled", + planeA & DISPPLANE_SEL_PIPE_MASK ? "Pipe B" : "Pipe A"); + if (pI830->availablePipes == 2) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Display plane B is now %s and connected to %s.\n", + pI830->planeEnabled[1] ? "enabled" : "disabled", + planeB & DISPPLANE_SEL_PIPE_MASK ? "Pipe B" : "Pipe A"); + /* XXX Plane C is ignored for now (overlay). */ /* @@ -2688,12 +3427,108 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) */ temp = INREG(PIPEACONF); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEACONF is 0x%08lx\n", temp); - if (IS_MOBILE(pI830)) { + if (pI830->availablePipes == 2) { temp = INREG(PIPEBCONF); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEBCONF is 0x%08lx\n", temp); } -#if PRINT_MODE_INFO + if (xf86IsEntityShared(pScrn->entityList[0])) { + /* Clean this up !! */ + if (IsPrimary(pScrn)) { + CARD32 stridereg = !pI830->pipe ? DSPASTRIDE : DSPBSTRIDE; + CARD32 basereg = !pI830->pipe ? DSPABASE : DSPBBASE; + CARD32 sizereg = !pI830->pipe ? DSPASIZE : DSPBSIZE; + I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); + + temp = INREG(stridereg); + if (temp / pI8301->cpp != pI830->entityPrivate->pScrn_1->displayWidth) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Correcting plane %c stride (%d -> %d)\n", PIPE_NAME(pI830->pipe), + (int)(temp / pI8301->cpp), pI830->entityPrivate->pScrn_1->displayWidth); + OUTREG(stridereg, pI830->entityPrivate->pScrn_1->displayWidth * pI8301->cpp); + } + OUTREG(sizereg, (pMode->HDisplay - 1) | ((pMode->VDisplay - 1) << 16)); + /* Trigger update */ + temp = INREG(basereg); + OUTREG(basereg, temp); + + if (pI830->entityPrivate && pI830->entityPrivate->pScrn_2) { + I830Ptr pI8302 = I830PTR(pI830->entityPrivate->pScrn_2); + stridereg = pI830->pipe ? DSPASTRIDE : DSPBSTRIDE; + basereg = pI830->pipe ? DSPABASE : DSPBBASE; + sizereg = pI830->pipe ? DSPASIZE : DSPBSIZE; + + temp = INREG(stridereg); + if (temp / pI8302->cpp != pI830->entityPrivate->pScrn_2->displayWidth) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Correcting plane %c stride (%d -> %d)\n", PIPE_NAME(!pI830->pipe), + (int)(temp / pI8302->cpp), pI830->entityPrivate->pScrn_2->displayWidth); + OUTREG(stridereg, pI830->entityPrivate->pScrn_2->displayWidth * pI8302->cpp); + } + OUTREG(sizereg, (pI830->entityPrivate->pScrn_2->currentMode->HDisplay - 1) | ((pI830->entityPrivate->pScrn_2->currentMode->VDisplay - 1) << 16)); + /* Trigger update */ + temp = INREG(basereg); + OUTREG(basereg, temp); + } + } else { + CARD32 stridereg = pI830->pipe ? DSPASTRIDE : DSPBSTRIDE; + CARD32 basereg = pI830->pipe ? DSPABASE : DSPBBASE; + CARD32 sizereg = pI830->pipe ? DSPASIZE : DSPBSIZE; + I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); + I830Ptr pI8302 = I830PTR(pI830->entityPrivate->pScrn_2); + + temp = INREG(stridereg); + if (temp / pI8301->cpp != pI830->entityPrivate->pScrn_1->displayWidth) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Correcting plane %c stride (%d -> %d)\n", PIPE_NAME(pI830->pipe), + (int)(temp / pI8301->cpp), pI830->entityPrivate->pScrn_1->displayWidth); + OUTREG(stridereg, pI830->entityPrivate->pScrn_1->displayWidth * pI8301->cpp); + } + OUTREG(sizereg, (pI830->entityPrivate->pScrn_1->currentMode->HDisplay - 1) | ((pI830->entityPrivate->pScrn_1->currentMode->VDisplay - 1) << 16)); + /* Trigger update */ + temp = INREG(basereg); + OUTREG(basereg, temp); + + stridereg = !pI830->pipe ? DSPASTRIDE : DSPBSTRIDE; + basereg = !pI830->pipe ? DSPABASE : DSPBBASE; + sizereg = !pI830->pipe ? DSPASIZE : DSPBSIZE; + + temp = INREG(stridereg); + if (temp / pI8302->cpp != pI830->entityPrivate->pScrn_2->displayWidth) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Correcting plane %c stride (%d -> %d)\n", PIPE_NAME(!pI830->pipe), + (int)(temp / pI8302->cpp), pI830->entityPrivate->pScrn_2->displayWidth); + OUTREG(stridereg, pI830->entityPrivate->pScrn_2->displayWidth * pI8302->cpp); + } + OUTREG(sizereg, (pMode->HDisplay - 1) | ((pMode->VDisplay - 1) << 16)); + /* Trigger update */ + temp = INREG(basereg); + OUTREG(basereg, temp); + } + } else { + for (i = 0; i < pI830->availablePipes; i++) { + CARD32 stridereg = i ? DSPBSTRIDE : DSPASTRIDE; + CARD32 basereg = i ? DSPBBASE : DSPABASE; + CARD32 sizereg = i ? DSPBSIZE : DSPASIZE; + + if (!pI830->planeEnabled[i]) + continue; + + temp = INREG(stridereg); + if (temp / pI830->cpp != pScrn->displayWidth) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Correcting plane %c stride (%d -> %d)\n", PIPE_NAME(i), + (int)(temp / pI830->cpp), pScrn->displayWidth); + OUTREG(stridereg, pScrn->displayWidth * pI830->cpp); + } + OUTREG(sizereg, (pMode->HDisplay - 1) | ((pMode->VDisplay - 1) << 16)); + /* Trigger update */ + temp = INREG(basereg); + OUTREG(basereg, temp); + } + } + +#if 0 /* Print out some CRTC/display information. */ temp = INREG(HTOTAL_A); ErrorF("Horiz active: %d, Horiz total: %d\n", temp & 0x7ff, @@ -2722,26 +3557,44 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) ErrorF("Plane A start offset is %d\n", temp); temp = INREG(DSPASTRIDE); ErrorF("Plane A stride is %d bytes (%d pixels)\n", temp, temp / pI830->cpp); -#endif - - for (i = 0; i < MAX_DISPLAY_PIPES; i++) { - CARD32 stridereg = i ? DSPBSTRIDE : DSPASTRIDE; - CARD32 basereg = i ? DSPBBASE : DSPABASE; - - if (!pI830->planeEnabled[i]) - continue; + temp = INREG(DSPAPOS); + ErrorF("Plane A position %d %d\n", temp & 0xffff, (temp & 0xffff0000) >> 16); + temp = INREG(DSPASIZE); + ErrorF("Plane A size %d %d\n", temp & 0xffff, (temp & 0xffff0000) >> 16); - temp = INREG(stridereg); - if (temp / pI830->cpp != pScrn->displayWidth) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Correcting plane %c stride (%d -> %d)\n", PIPE_NAME(i), - (int)(temp / pI830->cpp), pScrn->displayWidth); - OUTREG(stridereg, pScrn->displayWidth * pI830->cpp); - /* Trigger update */ - temp = INREG(basereg); - OUTREG(basereg, temp); - } - } + /* Print out some CRTC/display information. */ + temp = INREG(HTOTAL_B); + ErrorF("Horiz active: %d, Horiz total: %d\n", temp & 0x7ff, + (temp >> 16) & 0xfff); + temp = INREG(HBLANK_B); + ErrorF("Horiz blank start: %d, Horiz blank end: %d\n", temp & 0xfff, + (temp >> 16) & 0xfff); + temp = INREG(HSYNC_B); + ErrorF("Horiz sync start: %d, Horiz sync end: %d\n", temp & 0xfff, + (temp >> 16) & 0xfff); + temp = INREG(VTOTAL_B); + ErrorF("Vert active: %d, Vert total: %d\n", temp & 0x7ff, + (temp >> 16) & 0xfff); + temp = INREG(VBLANK_B); + ErrorF("Vert blank start: %d, Vert blank end: %d\n", temp & 0xfff, + (temp >> 16) & 0xfff); + temp = INREG(VSYNC_B); + ErrorF("Vert sync start: %d, Vert sync end: %d\n", temp & 0xfff, + (temp >> 16) & 0xfff); + temp = INREG(PIPEBSRC); + ErrorF("Image size: %dx%d (%dx%d)\n", + (temp >> 16) & 0x7ff, temp & 0x7ff, + (((temp >> 16) & 0x7ff) + 1), ((temp & 0x7ff) + 1)); + ErrorF("Pixel multiply is %d\n", (planeA >> 20) & 0x3); + temp = INREG(DSPBBASE); + ErrorF("Plane B start offset is %d\n", temp); + temp = INREG(DSPBSTRIDE); + ErrorF("Plane B stride is %d bytes (%d pixels)\n", temp, temp / pI830->cpp); + temp = INREG(DSPBPOS); + ErrorF("Plane B position %d %d\n", temp & 0xffff, (temp & 0xffff0000) >> 16); + temp = INREG(DSPBSIZE); + ErrorF("Plane B size %d %d\n", temp & 0xffff, (temp & 0xffff0000) >> 16); +#endif xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Mode bandwidth is %d Mpixel/s\n", pMode->HDisplay * pMode->VDisplay * refresh / 1000000); @@ -2790,6 +3643,8 @@ InitRegisterRec(ScrnInfoPtr pScrn) I830RegPtr i830Reg = &pI830->ModeReg; int i; + if (!IsPrimary(pScrn)) return; + for (i = 0; i < 8; i++) i830Reg->Fence[i] = 0; } @@ -3018,6 +3873,8 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) vgaHWPtr hwp; I830Ptr pI830; VisualPtr visual; + I830EntPtr pI830Ent = NULL; + I830Ptr pI8301 = NULL; #ifdef XF86DRI Bool driDisabled; #endif @@ -3026,8 +3883,56 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) pI830 = I830PTR(pScrn); hwp = VGAHWPTR(pScrn); + if (xf86IsEntityShared(pScrn->entityList[0])) { + pI830Ent = pI830->entityPrivate; + pI8301 = I830PTR(pI830Ent->pScrn_1); + + /* PreInit failed on the second head, so make sure we turn it off */ + if (IsPrimary(pScrn) && !pI830->entityPrivate->pScrn_2) { + if (pI830->pipe == 0) { + pI830->operatingDevices &= 0xFF; + } else { + pI830->operatingDevices &= 0xFF00; + } + } + } + pI830->starting = TRUE; + /* Alloc our pointers for the primary head */ + if (IsPrimary(pScrn)) { + if (!pI830->LpRing) + pI830->LpRing = xalloc(sizeof(I830RingBuffer)); + if (!pI830->CursorMem) + pI830->CursorMem = xalloc(sizeof(I830MemRange)); + if (!pI830->CursorMemARGB) + pI830->CursorMemARGB = xalloc(sizeof(I830MemRange)); + if (!pI830->OverlayMem) + pI830->OverlayMem = xalloc(sizeof(I830MemRange)); + if (!pI830->overlayOn) + pI830->overlayOn = xalloc(sizeof(Bool)); + if (!pI830->LpRing || !pI830->CursorMem || !pI830->CursorMemARGB || + !pI830->OverlayMem || !pI830->overlayOn) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Could not allocate primary data structures.\n"); + return FALSE; + } + *pI830->overlayOn = FALSE; + if (pI830->entityPrivate) + pI830->entityPrivate->XvInUse = -1; + } + + if (xf86IsEntityShared(pScrn->entityList[0])) { + /* Make our second head point to the first heads structures */ + if (!IsPrimary(pScrn)) { + pI830->LpRing = pI8301->LpRing; + pI830->CursorMem = pI8301->CursorMem; + pI830->CursorMemARGB = pI8301->CursorMemARGB; + pI830->OverlayMem = pI8301->OverlayMem; + pI830->overlayOn = pI8301->overlayOn; + } + } + /* * If we're changing the BIOS's view of the video memory size, do that * first, then re-initialise the VBE information. @@ -3058,6 +3963,12 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) #ifdef I830_XV pI830->XvEnabled = !pI830->XvDisabled; if (pI830->XvEnabled) { + if (!IsPrimary(pScrn)) { + if (!pI8301->XvEnabled || pI830->noAccel) { + pI830->XvEnabled = FALSE; + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Xv is disabled.\n"); + } + } else if (pI830->noAccel || pI830->StolenOnly) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Xv is disabled because it " "needs 2D accel and AGPGART.\n"); @@ -3068,12 +3979,15 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) pI830->XvEnabled = FALSE; #endif - I830ResetAllocations(pScrn, 0); + if (IsPrimary(pScrn)) { + I830ResetAllocations(pScrn, 0); - I830Allocate2DMemory(pScrn, ALLOC_INITIAL); + if (!I830Allocate2DMemory(pScrn, ALLOC_INITIAL)) + return FALSE; + } if (!pI830->noAccel) { - if (pI830->LpRing.mem.Size == 0) { + if (pI830->LpRing->mem.Size == 0) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling acceleration because the ring buffer " "allocation failed.\n"); @@ -3082,7 +3996,7 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) } if (!pI830->SWCursor) { - if (pI830->CursorMem.Size == 0) { + if (pI830->CursorMem->Size == 0) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling HW cursor because the cursor memory " "allocation failed.\n"); @@ -3097,7 +4011,7 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) "needs 2D acceleration.\n"); pI830->XvEnabled = FALSE; } - if (pI830->OverlayMem.Physical == 0) { + if (pI830->OverlayMem->Physical == 0) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling Xv because the overlay register buffer " "allocation failed.\n"); @@ -3149,15 +4063,17 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) * After the 3D allocations have been done, see if there's any free space * that can be added to the framebuffer allocation. */ - I830Allocate2DMemory(pScrn, 0); + if (IsPrimary(pScrn)) { + I830Allocate2DMemory(pScrn, 0); - DPRINTF(PFX, "assert(if(!I830DoPoolAllocation(pScrn, pI830->StolenPool)))\n"); - if (!I830DoPoolAllocation(pScrn, &(pI830->StolenPool))) - return FALSE; + DPRINTF(PFX, "assert(if(!I830DoPoolAllocation(pScrn, pI830->StolenPool)))\n"); + if (!I830DoPoolAllocation(pScrn, &(pI830->StolenPool))) + return FALSE; - DPRINTF(PFX, "assert( if(!I830FixupOffsets(pScrn)) )\n"); - if (!I830FixupOffsets(pScrn)) - return FALSE; + DPRINTF(PFX, "assert( if(!I830FixupOffsets(pScrn)) )\n"); + if (!I830FixupOffsets(pScrn)) + return FALSE; + } #ifdef XF86DRI if (pI830->directRenderingEnabled) { @@ -3171,7 +4087,13 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) return FALSE; pScrn->memPhysBase = (unsigned long)pI830->FbBase; - pScrn->fbOffset = pI830->FrontBuffer.Start; + + if (IsPrimary(pScrn)) { + pScrn->fbOffset = pI830->FrontBuffer.Start; + } else { + I830Ptr pI8301 = I830PTR(pI830Ent->pScrn_1); + pScrn->fbOffset = pI8301->FrontBuffer2.Start; + } pI830->xoffset = (pScrn->fbOffset / pI830->cpp) % pScrn->displayWidth; pI830->yoffset = (pScrn->fbOffset / pI830->cpp) / pScrn->displayWidth; @@ -3186,6 +4108,7 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) memset(&pI830->SavedReg, 0, sizeof(pI830->SavedReg)); DPRINTF(PFX, "assert( if(!I830BIOSEnterVT(scrnIndex, 0)) )\n"); + if (!I830BIOSEnterVT(scrnIndex, 0)) return FALSE; @@ -3215,16 +4138,22 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) xf86SetBlackWhitePixels(pScreen); -#if 1 I830DGAInit(pScreen); -#endif DPRINTF(PFX, "assert( if(!xf86InitFBManager(pScreen, &(pI830->FbMemBox))) )\n"); - if (!xf86InitFBManager(pScreen, &(pI830->FbMemBox))) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + if (IsPrimary(pScrn)) { + if (!xf86InitFBManager(pScreen, &(pI830->FbMemBox))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to init memory manager\n"); - return FALSE; + return FALSE; + } + } else { + if (!xf86InitFBManager(pScreen, &(pI8301->FbMemBox2))) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to init memory manager\n"); + return FALSE; + } } if (!pI830->noAccel) { @@ -3290,14 +4219,16 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) pScreen->SaveScreen = I830BIOSSaveScreen; pI830->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = I830BIOSCloseScreen; + + if (pI830->checkLid) + pI830->lidTimer = TimerSet(NULL, 0, 1000, I830LidTimer, pScrn); if (serverGeneration == 1) xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); -#if 0 + #ifdef I830DEBUG I830_dump_registers(pScrn); #endif -#endif pI830->starting = FALSE; pI830->closing = FALSE; @@ -3319,7 +4250,44 @@ I830BIOSAdjustFrame(int scrnIndex, int x, int y, int flags) DPRINTF(PFX, "I830BIOSAdjustFrame: y = %d (+ %d), x = %d (+ %d)\n", x, pI830->xoffset, y, pI830->yoffset); - VBESetDisplayStart(pVbe, x + pI830->xoffset, y + pI830->yoffset, TRUE); + /* The i830M just happens to have some problems programming offsets via + * this VESA BIOS call. Especially in dual head configurations which + * have high resolutions which cause the DSP{A,B}BASE registers to be + * programmed incorrectly. Thus, it warrants bypassing the BIOS for i830M + * and hitting the DSP{A,B}BASE registers directly. + * + * We could probably do this for other platforms too, but we don't + * know what else the Video BIOS may do when calling it. It seems safe + * though for i830M during testing...... + * + * Also note, calling the Video BIOS version first and then fixing the + * registers fail on i830M and eventually cause a lockup of the hardware + * in my testing. + */ + + if (pI830->Clone) { + if (!IS_I830(pI830)) { + SetBIOSPipe(pScrn, !pI830->pipe); + VBESetDisplayStart(pVbe, x + pI830->xoffset, y + pI830->yoffset, TRUE); + } else { + if (!pI830->pipe == 0) { + OUTREG(DSPABASE, pScrn->fbOffset + ((y * pScrn->displayWidth + x) * pI830->cpp)); + } else { + OUTREG(DSPBBASE, pScrn->fbOffset + ((y * pScrn->displayWidth + x) * pI830->cpp)); + } + } + } + + if (!IS_I830(pI830)) { + SetPipeAccess(pScrn); + VBESetDisplayStart(pVbe, x + pI830->xoffset, y + pI830->yoffset, TRUE); + } else { + if (pI830->pipe == 0) { + OUTREG(DSPABASE, pScrn->fbOffset + ((y * pScrn->displayWidth + x) * pI830->cpp)); + } else { + OUTREG(DSPBBASE, pScrn->fbOffset + ((y * pScrn->displayWidth + x) * pI830->cpp)); + } + } } static void @@ -3366,6 +4334,13 @@ I830BIOSLeaveVT(int scrnIndex, int flags) DPRINTF(PFX, "Leave VT\n"); + if (!IsPrimary(pScrn)) { + I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); + if (!pI8301->GttBound) { + return; + } + } + #ifdef XF86DRI if (pI830->directRenderingOpen) { DPRINTF(PFX, "calling dri lock\n"); @@ -3379,10 +4354,22 @@ I830BIOSLeaveVT(int scrnIndex, int flags) SaveHWOperatingState(pScrn); #endif + if (IsPrimary(pScrn)) { + if (!SetDisplayDevices(pScrn, pI830->savedDevices)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to switch back to original display devices (0x%x)\n", + pI830->savedDevices); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Successfully set original devices\n"); + } + } + ResetState(pScrn, TRUE); RestoreHWState(pScrn); RestoreBIOSMemSize(pScrn); - I830UnbindGARTMemory(pScrn); + if (IsPrimary(pScrn)) + I830UnbindGARTMemory(pScrn); if (pI830->AccelInfoRec) pI830->AccelInfoRec->NeedToSync = FALSE; } @@ -3398,8 +4385,20 @@ I830BIOSEnterVT(int scrnIndex, int flags) DPRINTF(PFX, "Enter VT\n"); - if (!I830BindGARTMemory(pScrn)) - return FALSE; + if (IsPrimary(pScrn)) { + if (!SetDisplayDevices(pScrn, pI830->operatingDevices)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to switch to configured display devices\n"); + return FALSE; + } + } + + /* Setup for checking lid status */ + pI830->monitorSwitch = INREG(SWF0) & 0x0000FFFF; + + if (IsPrimary(pScrn)) + if (!I830BindGARTMemory(pScrn)) + return FALSE; CheckInheritedState(pScrn); if (!TweakMemorySize(pScrn, pI830->newBIOSMemSize,FALSE)) @@ -3480,7 +4479,8 @@ I830BIOSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) #define BINDUNBIND 0 #endif #if BINDUNBIND - I830UnbindGARTMemory(pScrn); + if (IsPrimary(pScrn)) + I830UnbindGARTMemory(pScrn); #endif #ifdef I830_XV /* Give the video overlay code a chance to see the new mode. */ @@ -3493,7 +4493,8 @@ I830BIOSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) I830VideoSwitchModeAfter(pScrn, mode); #endif #if BINDUNBIND - I830BindGARTMemory(pScrn); + if (IsPrimary(pScrn)) + I830BindGARTMemory(pScrn); #endif return ret; @@ -3510,7 +4511,7 @@ I830BIOSSaveScreen(ScreenPtr pScreen, int mode) DPRINTF(PFX, "I830BIOSSaveScreen: %d, on is %s\n", mode, BOOLTOSTRING(on)); if (pScrn->vtSema) { - for (i = 0; i < MAX_DISPLAY_PIPES; i++) { + for (i = 0; i < pI830->availablePipes; i++) { if (i == 0) { ctrl = DSPACNTR; base = DSPABASE; @@ -3550,6 +4551,34 @@ I830DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, I830Ptr pI830 = I830PTR(pScrn); vbeInfoPtr pVbe = pI830->pVbe; + if (pI830->Clone) { + SetBIOSPipe(pScrn, !pI830->pipe); + if (xf86LoaderCheckSymbol("VBEDPMSSet")) { + VBEDPMSSet(pVbe, PowerManagementMode); + } else { + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x4f10; + pVbe->pInt10->bx = 0x01; + + switch (PowerManagementMode) { + case DPMSModeOn: + break; + case DPMSModeStandby: + pVbe->pInt10->bx |= 0x0100; + break; + case DPMSModeSuspend: + pVbe->pInt10->bx |= 0x0200; + break; + case DPMSModeOff: + pVbe->pInt10->bx |= 0x0400; + break; + } + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + } + } + + SetPipeAccess(pScrn); + if (xf86LoaderCheckSymbol("VBEDPMSSet")) { VBEDPMSSet(pVbe, PowerManagementMode); } else { @@ -3614,7 +4643,23 @@ I830BIOSCloseScreen(int scrnIndex, ScreenPtr pScreen) pI830->CursorInfoRec = 0; } - xf86GARTCloseScreen(scrnIndex); + if (IsPrimary(pScrn)) { + xf86GARTCloseScreen(scrnIndex); + + xfree(pI830->LpRing); + pI830->LpRing = NULL; + xfree(pI830->CursorMem); + pI830->CursorMem = NULL; + xfree(pI830->CursorMemARGB); + pI830->CursorMemARGB = NULL; + xfree(pI830->OverlayMem); + pI830->OverlayMem = NULL; + xfree(pI830->overlayOn); + pI830->overlayOn = NULL; + } + + if (pI830->lidTimer) + TimerCancel(pI830->lidTimer); pScrn->vtSema = FALSE; pI830->closing = FALSE; @@ -3695,6 +4740,65 @@ I830PMEvent(int scrnIndex, pmEvent event, Bool undo) return TRUE; } +static CARD32 +I830LidTimer(OsTimerPtr timer, CARD32 now, pointer arg) +{ + ScrnInfoPtr pScrn = (ScrnInfoPtr) arg; + I830Ptr pI830 = I830PTR(pScrn); + + if (pScrn->vtSema) { + /* Check for monitor lid being closed/opened and act accordingly */ + int temp = INREG(SWF0) & 0x0000FFFF; + + if (pI830->monitorSwitch != temp) { + int conf = pI830->operatingDevices; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Detected possible lid operation, fixing up.\n"); + if ((temp & 0x0808) == 0x0000) { + /* LFP (PIPE A or B) GOING OFF - PROBABLE LID CLOSURE */ + conf = pI830->operatingDevices & 0xF7F7; +#if 0 + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Lid is being closed.\n"); +#endif + } else { +#if 0 + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Lid is being opened.\n"); +#endif + } + + /* If we've defined our own monitors, then get them and set them + * up when switching in single head mode, no effect in dual heads + * NOTE: This assumes that the LCD is always on Pipe B..... */ + conf |= pI830->MonType1; + if (IsPrimary(pScrn)) { + if (!SetDisplayDevices(pScrn, conf)) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to switch " + "to configured display devices during lid operation.\n"); + } + pI830->monitorSwitch = conf; + + /* Now, when we're single head, make sure we switch pipes */ + if (!(xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone)) { + if ((temp & 0xFF00) == 0x0000) + pI830->pipe = 0; + if ((temp & 0x00FF) == 0x0000) + pI830->pipe = 1; + } + I830BIOSSwitchMode(pScrn->pScreen->myNum, pScrn->currentMode, 0); + I830BIOSAdjustFrame(pScrn->pScreen->myNum, pScrn->frameX0, pScrn->frameY0, 0); + + /* Everything should be o.k. now, so make sure the HW cursor is + * on the correct pipe */ + if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) { + pI830->CursorInfoRec->ShowCursor(pScrn); + pI830->cursorOn = TRUE; + } + } + } + + return 1000; +} + void I830InitpScrn(ScrnInfoPtr pScrn) { @@ -3708,5 +4812,3 @@ I830InitpScrn(ScrnInfoPtr pScrn) pScrn->ValidMode = I830ValidMode; pScrn->PMEvent = I830PMEvent; } - - |