diff options
Diffstat (limited to 'src/i830_driver.c')
-rw-r--r-- | src/i830_driver.c | 1472 |
1 files changed, 942 insertions, 530 deletions
diff --git a/src/i830_driver.c b/src/i830_driver.c index afc2bd41..85d3d739 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -222,8 +222,8 @@ typedef enum { OPTION_MONITOR_LAYOUT, OPTION_CLONE, OPTION_CLONE_REFRESH, - OPTION_CHECKLID, - OPTION_FLIP_PRIMARY + OPTION_CHECKDEVICES, + OPTION_FIXEDPIPE } I830Opts; static OptionInfoRec I830BIOSOptions[] = { @@ -241,8 +241,8 @@ static OptionInfoRec I830BIOSOptions[] = { {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}, + {OPTION_CHECKDEVICES, "CheckDevices",OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_FIXEDPIPE, "FixedPipe", OPTV_ANYSTR, {0}, FALSE}, {-1, NULL, OPTV_NONE, {0}, FALSE} }; /* *INDENT-ON* */ @@ -255,7 +255,7 @@ 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 CARD32 I830CheckDevicesTimer(OsTimerPtr timer, CARD32 now, pointer arg); static Bool SetPipeAccess(ScrnInfoPtr pScrn); static Bool IsPrimary(ScrnInfoPtr pScrn); @@ -397,7 +397,28 @@ Check5fStatus(ScrnInfoPtr pScrn, int func, int ax) } } -#if 0 +static int +GetToggleList(ScrnInfoPtr pScrn, int toggle) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + DPRINTF(PFX, "GetToggleList\n"); + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f64; + pVbe->pInt10->bx = 0x500; + + pVbe->pInt10->bx |= toggle; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Toggle (%d) 0x%x\n", toggle, pVbe->pInt10->cx); + return pVbe->pInt10->cx & 0xffff; + } + + return 0; +} + static int BitToRefresh(int bits) { @@ -410,7 +431,7 @@ BitToRefresh(int bits) } static int -GetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh, int *availRefresh) +GetRefreshRate(ScrnInfoPtr pScrn, int mode, int *availRefresh) { vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; @@ -420,8 +441,6 @@ 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; @@ -434,7 +453,6 @@ GetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh, int *availRefresh) } else return 0; } -#endif struct panelid { short hsize; @@ -593,6 +611,23 @@ SetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh) } static Bool +SetPowerStatus(ScrnInfoPtr pScrn, int mode) +{ + vbeInfoPtr pVbe = I830PTR(pScrn)->pVbe; + + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f64; + pVbe->pInt10->bx = 0x0800 | mode; + pVbe->pInt10->cx = 0x0000; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) + return TRUE; + + return FALSE; +} + +static Bool GetModeSupport(ScrnInfoPtr pScrn, int modePipeA, int modePipeB, int devicesPipeA, int devicesPipeB, int *maxBandwidth, int *bandwidthPipeA, int *bandwidthPipeB) @@ -604,7 +639,7 @@ GetModeSupport(ScrnInfoPtr pScrn, int modePipeA, int modePipeB, /* Only 8-bit mode numbers are supported. */ if ((modePipeA & 0x100) || (modePipeB & 0x100)) - return 0; + return FALSE; pVbe->pInt10->num = 0x10; pVbe->pInt10->ax = 0x5f28; @@ -709,9 +744,102 @@ GetDisplayDevices(ScrnInfoPtr pScrn) } } -/* 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 +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; + } + + /* failed, assume pipe A */ + return 0; +} + +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 || pI830->origPipe != pI830->pipe) { + if (!SetBIOSPipe(pScrn, pI830->pipe)) + return FALSE; + } + + return TRUE; +} + +static Bool +I830Set640x480(ScrnInfoPtr pScrn) +{ + I830Ptr pI830 = I830PTR(pScrn); + int m = 0x30; /* 640x480 8bpp */ + + switch (pScrn->depth) { + case 15: + m = 0x40; + break; + case 16: + m = 0x41; + break; + case 24: + m = 0x50; + break; + } + m |= (1 << 15) | (1 << 14); + return VBESetVBEMode(pI830->pVbe, m, NULL); +} + +/* This is needed for SetDisplayDevices to work correctly on I915G. + * Enable for all chipsets now as it has no bad side effects, apart * from slightly longer startup time. */ #define I915G_WORKAROUND @@ -722,35 +850,28 @@ SetDisplayDevices(ScrnInfoPtr pScrn, int devices) I830Ptr pI830 = I830PTR(pScrn); vbeInfoPtr pVbe = pI830->pVbe; CARD32 temp; + int singlepipe = 0; #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); + int getmode1; + Bool setmode = FALSE; #endif DPRINTF(PFX, "SetDisplayDevices: devices 0x%x\n", devices); + if (!pI830->specifiedMonitor) + return TRUE; + #ifdef I915G_WORKAROUND - if (pI830->bios_version >= 3272) { - VBEGetVBEMode(pVbe, &getmode); - I830VESASetVBEMode(pScrn, mode, NULL); + if (pI830->preinit) + setmode = TRUE; + if (pI830->leaving) + setmode = FALSE; + if (pI830->closing) + setmode = FALSE; + + if (setmode) { + VBEGetVBEMode(pVbe, &getmode1); + I830Set640x480(pScrn); } #endif @@ -762,40 +883,134 @@ SetDisplayDevices(ScrnInfoPtr pScrn, int devices) xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { #ifdef I915G_WORKAROUND - if (pI830->bios_version >= 3272) - I830VESASetVBEMode(pScrn, getmode, NULL); + if (setmode) { + VBESetVBEMode(pI830->pVbe, getmode1 | 1<<15, NULL); + } #endif + pI830->pipeEnabled[0] = (devices & 0xff) ? TRUE : FALSE; + pI830->pipeEnabled[1] = (devices & 0xff00) ? TRUE : FALSE; + return TRUE; } #ifdef I915G_WORKAROUND - if (pI830->bios_version >= 3272) - I830VESASetVBEMode(pScrn, getmode, NULL); + if (setmode) + VBESetVBEMode(pI830->pVbe, getmode1 | 1<<15, 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 (devices & 0xff) { + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f64; + pVbe->pInt10->bx = 0x1; + pVbe->pInt10->cx = devices & 0xff; - /* Now try to program the registers directly if the BIOS failed. - * This currently only turns on the CRT, but should be made to handle - * SDVO, TV, LFP etc. etc. - */ + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Successfully set display devices to 0x%x.\n",devices & 0xff); + singlepipe = devices & 0xff00; /* set alternate */ + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to set display devices to 0x%x.\n",devices & 0xff); + singlepipe = devices; + } + } else + singlepipe = devices; + + if (singlepipe == devices && devices & 0xff00) { + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5f64; + pVbe->pInt10->bx = 0x1; + pVbe->pInt10->cx = devices & 0xff00; + + xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); + if (Check5fStatus(pScrn, 0x5f64, pVbe->pInt10->ax)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Successfully set display devices to 0x%x.\n",devices & 0xff00); + singlepipe = devices & 0xff; /* set alternate */ + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to set display devices to 0x%x.\n",devices & 0xff00); + singlepipe = devices; + } + } + + /* LVDS doesn't exist on these */ + if (IS_I830(pI830) || IS_845G(pI830) || IS_I865G(pI830)) + singlepipe &= ~(PIPE_LFP | (PIPE_LFP<<8)); + + if (pI830->availablePipes == 1) + singlepipe &= 0xFF; + + /* Disable LVDS */ + if (singlepipe & PIPE_LFP) { + /* LFP on PipeA is unlikely! */ + OUTREG(0x61200, INREG(0x61200) & ~0x80000000); + OUTREG(0x61204, INREG(0x61204) & ~0x00000001); + while ((INREG(0x61200) & 0x80000000) || (INREG(0x61204) & 1)); + /* Fix up LVDS */ + OUTREG(LVDS, (INREG(LVDS) & ~1<<30) | 0x80000300); + /* Enable LVDS */ + OUTREG(0x61200, INREG(0x61200) | 0x80000000); + OUTREG(0x61204, INREG(0x61204) | 0x00000001); + while (!(INREG(0x61200) & 0x80000000) && !(INREG(0x61204) & 1)); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Enabling LVDS directly. Pipe A.\n"); + } else + if (singlepipe & (PIPE_LFP << 8)) { + OUTREG(0x61200, INREG(0x61200) & ~0x80000000); + OUTREG(0x61204, INREG(0x61204) & ~0x00000001); + while ((INREG(0x61200) & 0x80000000) || (INREG(0x61204) & 1)); + /* Fix up LVDS */ + OUTREG(LVDS, (INREG(LVDS) | 1<<30) | 0x80000300); + /* Enable LVDS */ + OUTREG(0x61200, INREG(0x61200) | 0x80000000); + OUTREG(0x61204, INREG(0x61204) | 0x00000001); + while (!(INREG(0x61200) & 0x80000000) && !(INREG(0x61204) & 1)); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Enabling LVDS directly. Pipe B.\n"); + } + else if (!(IS_I830(pI830) || IS_845G(pI830) || IS_I865G(pI830))) { + if (!(devices & (PIPE_LFP | PIPE_LFP<<8))) { + OUTREG(0x61200, INREG(0x61200) & ~0x80000000); + OUTREG(0x61204, INREG(0x61204) & ~0x00000001); + while ((INREG(0x61200) & 0x80000000) || (INREG(0x61204) & 1)); + /* Fix up LVDS */ + OUTREG(LVDS, (INREG(LVDS) | 1<<30) & ~0x80000300); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling LVDS directly.\n"); + } + } + + /* Now try to program the registers directly if the BIOS failed. */ temp = INREG(ADPA); - temp &= ~0xc0000c00; + temp &= ~(ADPA_DAC_ENABLE | ADPA_PIPE_SELECT_MASK); + temp &= ~(ADPA_VSYNC_CNTL_DISABLE | ADPA_HSYNC_CNTL_DISABLE); /* Turn on ADPA */ - if (devices & PIPE_CRT) { + if (singlepipe & PIPE_CRT) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "BIOS call failed, turning ADPA on directly. Pipe A.\n"); - temp |= 0x80000000; - } - if ((devices >> 8) & PIPE_CRT) { + "Enabling ADPA directly. Pipe A.\n"); + temp |= ADPA_DAC_ENABLE | ADPA_PIPE_A_SELECT; + OUTREG(ADPA, temp); + } else + if (singlepipe & (PIPE_CRT << 8)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "BIOS call failed, turning ADPA on directly. Pipe B.\n"); - temp |= 0xC0000000; + "Enabling ADPA directly. Pipe B.\n"); + temp |= ADPA_DAC_ENABLE | ADPA_PIPE_B_SELECT; + OUTREG(ADPA, temp); + } + else { + if (!(devices & (PIPE_CRT | PIPE_CRT<<8))) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling ADPA directly.\n"); + temp |= ADPA_VSYNC_CNTL_DISABLE | ADPA_HSYNC_CNTL_DISABLE; + OUTREG(ADPA, temp); + } } - OUTREG(ADPA, temp); + + xf86DrvMsg(pScrn->scrnIndex, X_WARNING,"Writing config directly to SWF0.\n"); + temp = INREG(SWF0); + OUTREG(SWF0, (temp & ~(0xffff)) | (devices & 0xffff)); if (GetDisplayDevices(pScrn) != devices) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, @@ -804,6 +1019,9 @@ SetDisplayDevices(ScrnInfoPtr pScrn, int devices) return FALSE; } + pI830->pipeEnabled[0] = (devices & 0xff) ? TRUE : FALSE; + pI830->pipeEnabled[1] = (devices & 0xff00) ? TRUE : FALSE; + return TRUE; } @@ -1480,95 +1698,97 @@ SetBIOSMemSize(ScrnInfoPtr pScrn, int newSize) } } -/* - * Use the native method instead of the vgahw method. So far this is - * only used for 8-bit mode. - * - * XXX Look into using the 10-bit gamma correction mode for 15/16/24 bit, - * and see if a DirectColor visual can be offered. - */ static void I830LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO * colors, VisualPtr pVisual) { I830Ptr pI830; - int i, index; + int i,j, index; unsigned char r, g, b; CARD32 val, temp; + int palreg; + int dspreg, dspbase; DPRINTF(PFX, "I830LoadPalette: numColors: %d\n", numColors); pI830 = I830PTR(pScrn); if (pI830->pipe == 0) { - /* It seems that an initial read is needed. */ - temp = INREG(PALETTE_A); + palreg = PALETTE_A; + dspreg = DSPACNTR; + dspbase = DSPABASE; + } else { + palreg = PALETTE_B; + dspreg = DSPBCNTR; + dspbase = DSPBBASE; + } + + if (pScrn->depth > 8) { + OUTREG(dspreg, INREG(dspreg) | DISPPLANE_GAMMA_ENABLE); + } else { + OUTREG(dspreg, INREG(dspreg) & ~DISPPLANE_GAMMA_ENABLE); + } + OUTREG(dspbase, INREG(dspbase)); + + /* It seems that an initial read is needed. */ + temp = INREG(palreg); + + switch(pScrn->depth) { + case 15: for (i = 0; i < numColors; i++) { - index = indices[i]; - r = colors[index].red; - g = colors[index].green; - b = colors[index].blue; - val = (r << 16) | (g << 8) | b; - OUTREG(PALETTE_A + index * 4, val); + index = indices[i]; + r = colors[index].red; + g = colors[index].green; + b = colors[index].blue; + for (j = 0; j < 8; j++) { + val = (r << 16) | (g << 8) | b; + OUTREG(palreg + index * 32 + (j * 4), val); + } } - } - if (pI830->pipe == 1) { - /* It seems that an initial read is needed. */ - temp = INREG(PALETTE_B); + break; + case 16: for (i = 0; i < numColors; i++) { + index = indices[i / 2]; + r = colors[index].red; + b = colors[index].blue; + index = indices[i]; + g = colors[index].green; + + val = (r << 16) | (g << 8) | b; + OUTREG(palreg + index * 16, val); + OUTREG(palreg + index * 16 + 4, val); + OUTREG(palreg + index * 16 + 8, val); + OUTREG(palreg + index * 16 + 12, val); + + i++; + index = indices[i]; + g = colors[index].green; + + val = (r << 16) | (g << 8) | b; + OUTREG(palreg + index * 16, val); + OUTREG(palreg + index * 16 + 4, val); + OUTREG(palreg + index * 16 + 8, val); + OUTREG(palreg + index * 16 + 12, val); + } + break; + default: + for(i = 0; i < numColors; i++) { index = indices[i]; r = colors[index].red; g = colors[index].green; b = colors[index].blue; val = (r << 16) | (g << 8) | b; - OUTREG(PALETTE_B + index * 4, val); + OUTREG(palreg + index * 4, val); } + break; } } -static void -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); - OUTREG(SWF4, pI830->saveSWF4); - } - if (pI830->MMIOBase) - I830UnmapMMIO(pScrn); - I830BIOSFreeRec(pScrn); -} - static int I830UseDDC(ScrnInfoPtr pScrn) { xf86MonPtr DDC = (xf86MonPtr)(pScrn->monitor->DDC); struct detailed_monitor_section* detMon; struct monitor_ranges *mon_range = NULL; - Bool ret = FALSE; int i; if (!DDC) return 0; @@ -1583,7 +1803,7 @@ I830UseDDC(ScrnInfoPtr pScrn) if (!mon_range || mon_range->min_h == 0 || mon_range->max_h == 0 || mon_range->min_v == 0 || mon_range->max_v == 0) - return FALSE; /* bad ddc */ + return 0; /* bad ddc */ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using detected DDC timings\n"); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\tHorizSync %d-%d\n", @@ -1597,7 +1817,7 @@ I830UseDDC(ScrnInfoPtr pScrn) pScrn->monitor->hsync[i].lo || (1.0 + DDC_SYNC_TOLERANCE) * mon_range->max_h < pScrn->monitor->hsync[i].hi) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "config file hsync range %g-%gkHz not within DDC " "hsync range %d-%dkHz\n", pScrn->monitor->hsync[i].lo, pScrn->monitor->hsync[i].hi, @@ -1614,7 +1834,7 @@ I830UseDDC(ScrnInfoPtr pScrn) pScrn->monitor->vrefresh[i].lo || (1.0 + DDC_SYNC_TOLERANCE) * mon_range->max_v < pScrn->monitor->vrefresh[i].hi) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "config file vrefresh range %g-%gHz not within DDC " "vrefresh range %d-%dHz\n", pScrn->monitor->vrefresh[i].lo, pScrn->monitor->vrefresh[i].hi, @@ -1628,75 +1848,43 @@ I830UseDDC(ScrnInfoPtr pScrn) return mon_range->max_clock; } -static int -GetBIOSPipe(ScrnInfoPtr pScrn) +static void +PreInitCleanup(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; + if (IsPrimary(pScrn)) + pI830->entityPrivate->pScrn_1 = NULL; + if (IsPrimary(pScrn) && pI830->LpRing) { + xfree(pI830->LpRing); + pI830->LpRing = NULL; } - - 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; + if (IsPrimary(pScrn) && pI830->CursorMem) { + xfree(pI830->CursorMem); + pI830->CursorMem = NULL; } - - 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; + if (IsPrimary(pScrn) && pI830->CursorMemARGB) { + xfree(pI830->CursorMemARGB); + pI830->CursorMemARGB = NULL; } - - return TRUE; + 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); + OUTREG(SWF4, pI830->saveSWF4); + } + if (pI830->MMIOBase) + I830UnmapMMIO(pScrn); + I830BIOSFreeRec(pScrn); } static Bool @@ -1728,7 +1916,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) int DDCclock = 0; char *s; DisplayModePtr p, pMon; - pointer pDDCModule, pVBEModule; + pointer pDDCModule = NULL, pVBEModule = NULL; Bool enable; const char *chipname; unsigned int ver; @@ -2096,8 +2284,19 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) } #endif + pI830->fixedPipe = -1; + if ((s = xf86GetOptValString(pI830->Options, OPTION_FIXEDPIPE)) && + IsPrimary(pScrn)) { + + if (strstr(s, "A") || strstr(s, "a") || strstr(s, "0")) + pI830->fixedPipe = 0; + else if (strstr(s, "B") || strstr(s, "b") || strstr(s, "1")) + pI830->fixedPipe = 1; + } + pI830->MonType1 = PIPE_NONE; pI830->MonType2 = PIPE_NONE; + pI830->specifiedMonitor = FALSE; if ((s = xf86GetOptValString(pI830->Options, OPTION_MONITOR_LAYOUT)) && IsPrimary(pScrn)) { @@ -2177,6 +2376,8 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) "Monitor 1 and 2 cannot be type NONE\n"); return FALSE; } + + pI830->specifiedMonitor = TRUE; } if (xf86ReturnOptValBool(pI830->Options, OPTION_CLONE, FALSE)) { @@ -2193,22 +2394,24 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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->Clone = TRUE; + } + + 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", + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Clone Monitor Refresh Rate %d\n", pI830->CloneRefresh); - } - /* See above i830refreshes on why 120Hz is commented out */ - if (pI830->CloneRefresh < 60 || pI830->CloneRefresh > 85 /* 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) { + /* See above i830refreshes on why 120Hz is commented out */ + if (pI830->CloneRefresh < 60 || pI830->CloneRefresh > 85 /* 120 */) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad Clone Refresh Rate\n"); + PreInitCleanup(pScrn); + return FALSE; + } + + 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"); @@ -2228,22 +2431,22 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) * Let's setup the mobile systems to check the lid status */ if (IS_MOBILE(pI830)) { - pI830->checkLid = TRUE; + pI830->checkDevices = TRUE; - if (!xf86ReturnOptValBool(pI830->Options, OPTION_CHECKLID, TRUE)) { - pI830->checkLid = FALSE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Checking Lid status disabled\n"); + if (!xf86ReturnOptValBool(pI830->Options, OPTION_CHECKDEVICES, TRUE)) { + pI830->checkDevices = FALSE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitoring connected displays disabled\n"); } else if (pI830->entityPrivate && !IsPrimary(pScrn) && - !I830PTR(pI830->entityPrivate->pScrn_1)->checkLid) { + !I830PTR(pI830->entityPrivate->pScrn_1)->checkDevices) { /* 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; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitoring connected displays disabled\n"); + pI830->checkDevices = FALSE; } else - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Checking Lid status enabled\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitoring connected displays enabled\n"); } else - pI830->checkLid = FALSE; + pI830->checkDevices = FALSE; /* * The "VideoRam" config file parameter specifies the total amount of @@ -2446,8 +2649,11 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS Build: %d\n",pI830->bios_version); - /* BIOS build 3062 changed the pipe switching functionality */ + if (IS_I915G(pI830) || IS_I915GM(pI830)) + pI830->newPipeSwitch = TRUE; + else if (pI830->availablePipes == 2 && pI830->bios_version >= 3062) { + /* BIOS build 3062 changed the pipe switching functionality */ pI830->newPipeSwitch = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using new Pipe switch code\n"); } else @@ -2481,18 +2687,29 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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; + pI830->pipe = pI830->origPipe = GetBIOSPipe(pScrn); + + /* Override */ + if (pI830->fixedPipe != -1) { + if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) { + pI830->pipe = pI830->fixedPipe; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Fixed Pipe setting primary to pipe %s.\n", + pI830->fixedPipe ? "B" : "A"); + } } - + /* If the monitors aren't setup, read from the current config */ - if (pI830->MonType1 == PIPE_NONE) + if (pI830->MonType1 == PIPE_NONE && pI830->MonType2 == PIPE_NONE) { pI830->MonType1 = pI830->savedDevices & 0xff; - if (pI830->MonType2 == PIPE_NONE) pI830->MonType2 = (pI830->savedDevices & 0xff00) >> 8; + } else { + /* Here, we've switched pipes from our primary */ + if (pI830->MonType1 == PIPE_NONE && pI830->pipe == 0) + pI830->pipe = 1; + if (pI830->MonType2 == PIPE_NONE && pI830->pipe == 1) + pI830->pipe = 0; + } pI830->operatingDevices = (pI830->MonType2 << 8) | pI830->MonType1; @@ -2504,15 +2721,18 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) 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); } + + if (pI830->pipe != pI830->origPipe) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Primary Pipe has been switched from original pipe (%s to %s)\n", + pI830->origPipe ? "B" : "A", pI830->pipe ? "B" : "A"); } else { I830Ptr pI8301 = I830PTR(pI830Ent->pScrn_1); pI830->operatingDevices = pI8301->operatingDevices; + pI830->pipe = !pI8301->pipe; + pI830->MonType1 = pI8301->MonType1; + pI830->MonType2 = pI8301->MonType2; } /* Buggy BIOS 3066 is known to cause this, so turn this off */ @@ -2540,26 +2760,25 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) return FALSE; } - if (!SetDisplayDevices(pScrn, pI830->operatingDevices)) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + if (IsPrimary(pScrn)) { + 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, + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Please check the devices specified in your MonitorLayout\n"); - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "is configured correctly.\n"); - PreInitCleanup(pScrn); - return FALSE; + 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; @@ -2604,7 +2823,9 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) pI830->CursorNeedsPhysical = FALSE; /* Force ring buffer to be in low memory for the 845G and later. */ +#if 0 if (IS_845G(pI830) || IS_I85X(pI830) || IS_I865G(pI830) || IS_I915G(pI830) || IS_I915GM(pI830)) +#endif pI830->NeedRingBufferLow = TRUE; /* @@ -2645,24 +2866,16 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) SetPipeAccess(pScrn); - if ((pDDCModule = xf86LoadSubModule(pScrn, "ddc")) == NULL) { - PreInitCleanup(pScrn); - return FALSE; - } - /* Check we have an LFP connected, before trying to * read PanelID information. */ if ( (pI830->pipe == 1 && pI830->operatingDevices & (PIPE_LFP << 8)) || - (pI830->pipe == 0 && pI830->operatingDevices & PIPE_LFP) ) { + (pI830->pipe == 0 && pI830->operatingDevices & PIPE_LFP) ) vbeDoPanelID(pI830->pVbe); - } - /* If we managed to get PanelID, then try EDID too, and if we get that - * it'll override the PanelID information above */ - if (!pI830->vesa->monitor && - (pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule)) != NULL) { - xf86PrintEDID(pI830->vesa->monitor); - } + pDDCModule = xf86LoadSubModule(pScrn, "ddc"); + + pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule); + if ((pScrn->monitor->DDC = pI830->vesa->monitor) != NULL) xf86SetDDCproperties(pScrn, pI830->vesa->monitor); xf86UnloadSubModule(pDDCModule); @@ -2772,11 +2985,9 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) /* * Note: VBE modes (> 0x7f) won't work with Intel's extended BIOS - * functions. For that reason it's important to set only - * V_MODETYPE_VGA in the flags. + * functions. */ - pScrn->modePool = i830GetModePool(pScrn, pI830->pVbe, pI830->vbeInfo, - V_MODETYPE_VGA); + pScrn->modePool = I830GetModePool(pScrn, pI830->pVbe, pI830->vbeInfo); if (!pScrn->modePool) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, @@ -3001,7 +3212,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) #endif SetPipeAccess(pScrn); - i830PrintModes(pScrn); + I830PrintModes(pScrn); if (!pI830->vesa->useDefaultRefresh) { /* @@ -3012,7 +3223,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) * if there are no non-CRT devices attached. */ SetPipeAccess(pScrn); - i830SetModeParameters(pScrn, pI830->pVbe); + I830SetModeParameters(pScrn, pI830->pVbe); } /* PreInit shouldn't leave any state changes, so restore this. */ @@ -3051,11 +3262,6 @@ 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. */ @@ -3064,7 +3270,9 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) xf86SetOperatingState(resVgaMem, pI830->pEnt->index, ResDisableOpr); VBEFreeVBEInfo(pI830->vbeInfo); + pI830->vbeInfo = NULL; vbeFree(pI830->pVbe); + pI830->pVbe = NULL; /* Use the VBE mode restore workaround by default. */ pI830->vbeRestoreWorkaround = TRUE; @@ -3283,12 +3491,16 @@ SaveHWState(ScrnInfoPtr pScrn) DPRINTF(PFX, "SaveHWState\n"); - SetPipeAccess(pScrn); + if (IsPrimary(pScrn) && pI830->pipe != pI830->origPipe) + SetBIOSPipe(pScrn, pI830->origPipe); + else + SetPipeAccess(pScrn); pVesa = pI830->vesa; /* Make sure we save at least this information in case of failure. */ VBEGetVBEMode(pVbe, &pVesa->stateMode); + pVesa->stateRefresh = GetRefreshRate(pScrn, pVesa->stateMode, NULL); modeInfo = VBEGetModeInfo(pVbe, pVesa->stateMode); pVesa->savedScanlinePitch = 0; if (modeInfo) { @@ -3354,6 +3566,11 @@ RestoreHWState(ScrnInfoPtr pScrn) DPRINTF(PFX, "RestoreHWState\n"); + if (IsPrimary(pScrn) && pI830->pipe != pI830->origPipe) + SetBIOSPipe(pScrn, pI830->origPipe); + else + SetPipeAccess(pScrn); + pVesa = pI830->vesa; /* @@ -3361,26 +3578,8 @@ RestoreHWState(ScrnInfoPtr pScrn) * Temporarily program a 640x480 mode before switching back to * text mode. */ - if (pVesa->useDefaultRefresh) { - int mode = 0; - - switch (pScrn->depth) { - case 8: - mode = 0x30; - break; - case 15: - mode = 0x40; - break; - case 16: - mode = 0x41; - break; - case 24: - mode = 0x50; - break; - } - mode |= (1 << 15) | (1 << 14); - I830VESASetVBEMode(pScrn, mode, NULL); - } + if (pVesa->useDefaultRefresh) + I830Set640x480(pScrn); if (pVesa->state && pVesa->stateSize) { CARD16 imr = INREG16(IMR); @@ -3413,6 +3612,9 @@ RestoreHWState(ScrnInfoPtr pScrn) "Setting the original video mode instead of restoring\n\t" "the saved state\n"); I830VESASetVBEMode(pScrn, pVesa->stateMode, NULL); + if (!pVesa->useDefaultRefresh && pI830->useExtendedRefresh) { + SetRefreshRate(pScrn, pVesa->stateMode, pVesa->stateRefresh); + } } if (pVesa->savedScanlinePitch) VBESetLogicalScanline(pVbe, pVesa->savedScanlinePitch); @@ -3424,13 +3626,10 @@ RestoreHWState(ScrnInfoPtr pScrn) vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS); vgaHWLock(hwp); + return TRUE; } -#ifndef USE_VBE -#define USE_VBE 1 -#endif - static void I830SetCloneVBERefresh(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock * block, int refresh) { I830Ptr pI830 = I830PTR(pScrn); @@ -3466,8 +3665,7 @@ static void I830SetCloneVBERefresh(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock #endif if (clock) block->PixelClock = clock; - block->RefreshRate = ((double)(block->PixelClock) / - (double)(p->HTotal * p->VTotal)) * 100; + block->RefreshRate = RefreshRate; return; } } @@ -3477,62 +3675,137 @@ static Bool I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock * block) { I830Ptr pI830 = I830PTR(pScrn); + Bool ret = FALSE; + int Mon; DPRINTF(PFX, "Setting mode 0x%.8x\n", mode); - if (pI830->Clone && !pI830->preinit) { + if (pI830->Clone && pI830->CloneHDisplay && pI830->CloneVDisplay && + !pI830->preinit && !pI830->closing) { VbeCRTCInfoBlock newblock; - int Mon; + int newmode = mode; - if (pI830->pipe == 0) + if (pI830->pipe == 1) Mon = pI830->MonType1; else Mon = pI830->MonType2; 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 */ + /* Now recheck refresh operations we can use */ + pI830->useExtendedRefresh = FALSE; + pI830->vesa->useDefaultRefresh = FALSE; + + if (Mon != PIPE_CRT) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "A non-CRT device is attached to Clone pipe %c.\n" + "\tNo refresh rate overrides will be attempted (0x%x).\n", + PIPE_NAME(!pI830->pipe), newmode); + 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; + + newmode |= 1 << 11; + if (pI830->vesa->useDefaultRefresh) + newmode &= ~(1 << 11); + 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) + (newmode & (1 << 11))) { + if (!SetRefreshRate(pScrn, newmode, 60)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "BIOS call 0x5f05 not supported on Clone Head, " + "setting refresh with VBE 3 method.\n"); + pI830->useExtendedRefresh = FALSE; + } + } + + if (!pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh) { + I830SetCloneVBERefresh(pScrn, newmode, &newblock, pI830->CloneRefresh * 100); + + if (!VBESetVBEMode(pI830->pVbe, newmode, &newblock)) { + if (!VBESetVBEMode(pI830->pVbe, (newmode & ~(1 << 11)), NULL)) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to set mode for Clone head.\n"); + else + newmode &= ~(1 << 11); + } + } else { + if (!VBESetVBEMode(pI830->pVbe, (newmode & ~(1 << 11)), NULL)) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to set mode for Clone head.\n"); + } + + if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh && + (newmode & (1 << 11))) { + if (!SetRefreshRate(pScrn, newmode, pI830->CloneRefresh)) xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to setup clone head mode resolution and refresh.\n"); + "Failed to set refresh rate to %dHz on Clone head.\n", + pI830->CloneRefresh); else - VBESetVBEMode(pI830->pVbe, mode, &newblock); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Set refresh rate to %dHz on Clone head.\n", + pI830->CloneRefresh); } + SetPipeAccess(pScrn); } - SetPipeAccess(pScrn); + if (pI830->pipe == 0) + Mon = pI830->MonType1; + else + Mon = pI830->MonType2; -#if USE_VBE - return VBESetVBEMode(pI830->pVbe, mode, block); -#else - { - vbeInfoPtr pVbe = pI830->pVbe; - pVbe->pInt10->num = 0x10; - pVbe->pInt10->ax = 0x80 | (mode & 0x7f); - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - pVbe->pInt10->ax = 0x0f00; - xf86ExecX86int10_wrapper(pVbe->pInt10, pScrn); - if ((pVbe->pInt10->ax & 0x7f) == (mode & 0x7f)) - return TRUE; - else - return FALSE; + /* Now recheck refresh operations we can use */ + pI830->useExtendedRefresh = FALSE; + pI830->vesa->useDefaultRefresh = FALSE; + + if (Mon != PIPE_CRT) + pI830->vesa->useDefaultRefresh = TRUE; + + mode |= 1 << 11; + if (pI830->vesa->useDefaultRefresh) + mode &= ~(1 << 11); + /* + * 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 (!SetRefreshRate(pScrn, mode, 60)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "BIOS call 0x5f05 not supported, " + "setting refresh with VBE 3 method.\n"); + pI830->useExtendedRefresh = FALSE; } -#endif + + if (!pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh && block) { + ret = VBESetVBEMode(pI830->pVbe, mode, block); + if (!ret) + ret = VBESetVBEMode(pI830->pVbe, (mode & ~(1 << 11)), NULL); + } else { + ret = VBESetVBEMode(pI830->pVbe, (mode & ~(1 << 11)), NULL); + } + + /* Might as well bail now if we've failed */ + if (!ret) return FALSE; + + if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh && + (mode & (1 << 11)) && block) { + if (!SetRefreshRate(pScrn, mode, block->RefreshRate / 100)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to set refresh rate to %dHz.\n", + block->RefreshRate / 100); + pI830->useExtendedRefresh = FALSE; + } + } + + return ret; } static Bool @@ -3561,21 +3834,6 @@ 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; @@ -3593,20 +3851,11 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) if (pI830->vesa->useDefaultRefresh) mode &= ~(1 << 11); + SetPipeAccess(pScrn); + if (I830VESASetVBEMode(pScrn, mode, data->block) == FALSE) { - if ((data->block && (mode & (1 << 11))) && - I830VESASetVBEMode(pScrn, (mode & ~(1 << 11)), NULL) == TRUE) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Set VBE Mode rejected this modeline.\n\t" - "Trying standard mode instead!\n"); - DPRINTF(PFX, "OOPS!\n"); - xfree(data->block); - data->block = NULL; - data->mode &= ~(1 << 11); - } else { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n"); - return FALSE; - } + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n"); + return FALSE; } /* @@ -3632,49 +3881,6 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) VBESetGetDACPaletteFormat(pVbe, 8); } - /* - * When it's OK to set better than default refresh rates, set them here. - */ - if (pI830->Clone) { - int Mon; - if (pI830->pipe == 0) - Mon = pI830->MonType1; - else - Mon = pI830->MonType2; - 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, - "Not attempting to override default refresh on non-CRT clone head\n"); - } - } - - 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; - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to set refresh rate to %dHz.\n", - data->block->RefreshRate / 100); - } - } - /* XXX Fix plane A with pipe A, and plane B with pipe B. */ planeA = INREG(DSPACNTR); planeB = INREG(DSPBCNTR); @@ -3690,36 +3896,18 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) pI830->planeEnabled[1] ? "enabled" : "disabled", planeB & DISPPLANE_SEL_PIPE_MASK ? "Pipe B" : "Pipe A"); - if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) { + if (pI830->operatingDevices & 0xff) { pI830->planeEnabled[0] = 1; - pI830->pipeEnabled[0] = 1; - pI830->planeEnabled[1] = 1; - pI830->pipeEnabled[1] = 1; + } else { + pI830->planeEnabled[0] = 0; } - /* - * Sometimes it seems that no display planes are enabled at this point. - * For mobile platforms pick the plane(s) connected to enabled pipes. - * For others choose plane A. - */ - if (!pI830->planeEnabled[0] && !pI830->planeEnabled[1]) { - if (pI830->availablePipes == 2) { - if ((pI830->pipeEnabled[0] && - ((planeA & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_A)) || - (pI830->pipeEnabled[1] && - ((planeA & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_B))) { - pI830->planeEnabled[0] = TRUE; - } - if ((pI830->pipeEnabled[0] && - ((planeB & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_A)) || - (pI830->pipeEnabled[1] && - ((planeB & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE_B))) { - pI830->planeEnabled[1] = TRUE; - } - } else { - pI830->planeEnabled[0] = TRUE; - } + if (pI830->operatingDevices & 0xff00) { + pI830->planeEnabled[1] = 1; + } else { + pI830->planeEnabled[1] = 0; } + if (pI830->planeEnabled[0]) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling plane A.\n"); planeA |= DISPLAY_PLANE_ENABLE; @@ -3763,6 +3951,8 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PIPEBCONF is 0x%08lx\n", temp); } + + if (xf86IsEntityShared(pScrn->entityList[0])) { /* Clean this up !! */ if (IsPrimary(pScrn)) { @@ -3941,6 +4131,7 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) } } +#if 0 { int ret; @@ -3950,6 +4141,7 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) "LFP compensation mode: 0x%x\n", ret); } } +#endif #if MODESWITCH_RESET_STATE ResetState(pScrn, TRUE); @@ -4268,26 +4460,22 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) * If we're changing the BIOS's view of the video memory size, do that * first, then re-initialise the VBE information. */ + if (pI830->pVbe) + vbeFree(pI830->pVbe); pI830->pVbe = VBEInit(NULL, pI830->pEnt->index); if (!TweakMemorySize(pScrn, pI830->newBIOSMemSize,FALSE)) SetBIOSMemSize(pScrn, pI830->newBIOSMemSize); if (!pI830->pVbe) return FALSE; + if (pI830->vbeInfo) + VBEFreeVBEInfo(pI830->vbeInfo); pI830->vbeInfo = VBEGetVBEInfo(pI830->pVbe); miClearVisualTypes(); - if (!xf86SetDefaultVisual(pScrn, -1)) - return FALSE; - if (pScrn->bitsPerPixel > 8) { - if (!miSetVisualTypes(pScrn->depth, TrueColorMask, - pScrn->rgbBits, TrueColor)) - return FALSE; - } else { - if (!miSetVisualTypes(pScrn->depth, + if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, pScrn->defaultVisual)) return FALSE; - } if (!miSetPixmapDepths()) return FALSE; @@ -4366,7 +4554,7 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) */ if (pI830->directRenderingEnabled) { - if (pI830->noAccel || pI830->SWCursor || pI830->StolenOnly) { + if (pI830->noAccel || pI830->SWCursor || (pI830->StolenOnly && IsPrimary(pScrn))) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DRI is disabled because it " "needs HW cursor, 2D accel and AGPGART.\n"); pI830->directRenderingEnabled = FALSE; @@ -4513,7 +4701,8 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) DPRINTF(PFX, "assert( if(!xf86HandleColormaps(pScreen, ...)) )\n"); if (!xf86HandleColormaps(pScreen, 256, 8, I830LoadPalette, 0, - CMAP_RELOAD_ON_MODE_SWITCH)) { + CMAP_RELOAD_ON_MODE_SWITCH | + CMAP_PALETTED_TRUECOLOR)) { return FALSE; } @@ -4551,9 +4740,6 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) 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); @@ -4665,12 +4851,24 @@ I830BIOSLeaveVT(int scrnIndex, int flags) DPRINTF(PFX, "Leave VT\n"); + pI830->leaving = TRUE; + + if (pI830->devicesTimer) + TimerCancel(pI830->devicesTimer); + pI830->devicesTimer = NULL; + + if (pI830->Clone) { + /* Ensure we don't try and setup modes on a clone head */ + pI830->CloneHDisplay = 0; + pI830->CloneVDisplay = 0; + } + if (!IsPrimary(pScrn)) { I830Ptr pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); if (!pI8301->GttBound) { return; } - } + } #ifdef XF86DRI if (pI830->directRenderingOpen) { @@ -4687,7 +4885,22 @@ I830BIOSLeaveVT(int scrnIndex, int flags) SaveHWOperatingState(pScrn); #endif + if (pI830->CursorInfoRec && pI830->CursorInfoRec->HideCursor) + pI830->CursorInfoRec->HideCursor(pScrn); + ResetState(pScrn, TRUE); + + 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"); + } + } + RestoreHWState(pScrn); RestoreBIOSMemSize(pScrn); if (IsPrimary(pScrn)) @@ -4695,14 +4908,15 @@ I830BIOSLeaveVT(int scrnIndex, int flags) if (pI830->AccelInfoRec) pI830->AccelInfoRec->NeedToSync = FALSE; + /* DO IT AGAIN! AS IT SEEMS THAT SOME LFPs FLICKER OTHERWISE */ if (IsPrimary(pScrn)) { if (!SetDisplayDevices(pScrn, pI830->savedDevices)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to switch back to original display devices (0x%x)\n", + "Failed to switch back to original display devices (0x%x) (2)\n", pI830->savedDevices); } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Successfully set original devices\n"); + "Successfully set original devices (2)\n"); } } } @@ -4711,10 +4925,9 @@ static Bool I830DetectMonitorChange(ScrnInfoPtr pScrn) { I830Ptr pI830 = I830PTR(pScrn); - pointer pDDCModule; + pointer pDDCModule = NULL; DisplayModePtr p, pMon; - xf86MonPtr DDC; - int i, memsize; + int memsize; int DDCclock = 0; int displayWidth = pScrn->displayWidth; int curHDisplay = pScrn->currentMode->HDisplay; @@ -4725,12 +4938,10 @@ I830DetectMonitorChange(ScrnInfoPtr pScrn) SetPipeAccess(pScrn); /* Re-read EDID */ - if ((pDDCModule = xf86LoadSubModule(pScrn, "ddc")) == NULL) - return FALSE; + pDDCModule = xf86LoadSubModule(pScrn, "ddc"); if (pI830->vesa->monitor) xfree(pI830->vesa->monitor); - if ((pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule)) != NULL) - xf86PrintEDID(pI830->vesa->monitor); + pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule); xf86UnloadSubModule(pDDCModule); if ((pScrn->monitor->DDC = pI830->vesa->monitor) != NULL) xf86SetDDCproperties(pScrn, pI830->vesa->monitor); @@ -4745,11 +4956,9 @@ I830DetectMonitorChange(ScrnInfoPtr pScrn) /* * Note: VBE modes (> 0x7f) won't work with Intel's extended BIOS - * functions. For that reason it's important to set only - * V_MODETYPE_VGA in the flags. + * functions. */ - pScrn->modePool = i830GetModePool(pScrn, pI830->pVbe, pI830->vbeInfo, - V_MODETYPE_VGA); + pScrn->modePool = I830GetModePool(pScrn, pI830->pVbe, pI830->vbeInfo); if (!pScrn->modePool) { /* This is bad, which would cause the Xserver to exit, maybe @@ -4774,6 +4983,7 @@ I830DetectMonitorChange(ScrnInfoPtr pScrn) pScrn->display->virtualY, memsize, LOOKUP_BEST_REFRESH); +if (DDCclock > 0) { p = pScrn->modes; if (p == NULL) return FALSE; @@ -4799,11 +5009,15 @@ I830DetectMonitorChange(ScrnInfoPtr pScrn) } p = p->next; } while (p != NULL && p != pScrn->modes); +} pScrn->displayWidth = displayWidth; /* restore old displayWidth */ xf86PruneDriverModes(pScrn); - i830PrintModes(pScrn); + I830PrintModes(pScrn); + + if (!pI830->vesa->useDefaultRefresh) + I830SetModeParameters(pScrn, pI830->pVbe); /* Now check if the previously used mode is o.k. for the current monitor. * This allows VT switching to continue happily when not disconnecting @@ -4849,6 +5063,32 @@ I830DetectMonitorChange(ScrnInfoPtr pScrn) return TRUE; } + +Bool +I830CheckModeSupport(ScrnInfoPtr pScrn, int x, int y, int mode) +{ + I830Ptr pI830 = I830PTR(pScrn); + Bool ret = TRUE; + + if (pI830->Clone) { + if (pI830->pipeDisplaySize[0].x2 != 0) { + if (x > pI830->pipeDisplaySize[0].x2 || + y > pI830->pipeDisplaySize[0].y2) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Bad Clone Mode removing\n"); + return FALSE; + } + } + if (pI830->pipeDisplaySize[1].x2 != 0) { + if (x > pI830->pipeDisplaySize[1].x2 || + y > pI830->pipeDisplaySize[1].y2) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Bad Clone Mode removing\n"); + return FALSE; + } + } + } + + return ret; +} /* * This gets called when gaining control of the VT, and from ScreenInit(). @@ -4861,19 +5101,34 @@ I830BIOSEnterVT(int scrnIndex, int flags) DPRINTF(PFX, "Enter VT\n"); + /* + * Only save state once per server generation since that's what most + * drivers do. Could change this to save state at each VT enter. + */ + if (pI830->SaveGeneration != serverGeneration) { + pI830->SaveGeneration = serverGeneration; + SaveHWState(pScrn); + } + + pI830->leaving = FALSE; + if (IsPrimary(pScrn)) { /* * This is needed for restoring from ACPI modes (especially S3) * so that we warmboot the Video BIOS. Some platforms have problems, * warm booting when we don't need to, so check that we can call - * the Video BIOS with our display devices, and only when that fails, + * the Video BIOS with our saved devices, and only when that fails, * we'll warm boot it. */ - if (!SetDisplayDevices(pScrn, pI830->operatingDevices)) { - xf86Int10InfoPtr pInt = xf86InitInt10(pI830->pEnt->index); + /* Check Pipe conf registers or possibly HTOTAL/VTOTAL for 0x00000000)*/ + CARD32 temp = pI830->pipe ? INREG(PIPEBCONF) : INREG(PIPEACONF); + if (!I830Set640x480(pScrn) || !(temp & 0x80000000)) { + xf86Int10InfoPtr pInt; xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "SetDisplayDevices failed, re-trying.\n"); + "Detected resume, re-POSTing.\n"); + + pInt = xf86InitInt10(pI830->pEnt->index); /* Now perform our warm boot */ if (pInt) { @@ -4885,17 +5140,17 @@ I830BIOSEnterVT(int scrnIndex, int flags) xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Re-POSTing via int10 failed, trying to continue.\n"); } - - /* Finally, re-setup the display devices */ - if (!SetDisplayDevices(pScrn, pI830->operatingDevices)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + } + + /* Finally, re-setup the display devices */ + if (!SetDisplayDevices(pScrn, pI830->operatingDevices)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to switch to configured display devices\n"); - return FALSE; - } + return FALSE; } } - /* Setup for checking lid status */ + /* Setup for device monitoring status */ pI830->monitorSwitch = INREG(SWF0) & 0x0000FFFF; if (IsPrimary(pScrn)) @@ -4906,14 +5161,6 @@ I830BIOSEnterVT(int scrnIndex, int flags) if (!TweakMemorySize(pScrn, pI830->newBIOSMemSize,FALSE)) SetBIOSMemSize(pScrn, pI830->newBIOSMemSize); - /* - * Only save state once per server generation since that's what most - * drivers do. Could change this to save state at each VT enter. - */ - if (pI830->SaveGeneration != serverGeneration) { - pI830->SaveGeneration = serverGeneration; - SaveHWState(pScrn); - } ResetState(pScrn, FALSE); SetHWOperatingState(pScrn); @@ -4946,7 +5193,7 @@ I830BIOSEnterVT(int scrnIndex, int flags) #ifdef XF86DRI if (pI830->directRenderingEnabled) { if (!pI830->starting) { - /* gdg DRM driver 1.2 supports resume */ + /* i915 DRM driver 1.2 supports resume */ if (pI830->drmMinor >= 2) I830DRIResume(screenInfo.screens[scrnIndex]); @@ -4962,6 +5209,9 @@ I830BIOSEnterVT(int scrnIndex, int flags) } #endif + if (pI830->checkDevices) + pI830->devicesTimer = TimerSet(NULL, 0, 1000, I830CheckDevicesTimer, pScrn); + return TRUE; } @@ -4969,8 +5219,6 @@ static Bool I830BIOSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) { - int _head; - int _tail; ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; I830Ptr pI830 = I830PTR(pScrn); int ret = TRUE; @@ -4978,13 +5226,8 @@ I830BIOSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) DPRINTF(PFX, "I830BIOSSwitchMode: mode == %p\n", mode); /* Stops head pointer freezes for 845G */ - if (!pI830->noAccel && (1 || IS_845G(pI830))) { - do { - _head = INREG(LP_RING + RING_HEAD) & I830_HEAD_MASK; - _tail = INREG(LP_RING + RING_TAIL) & I830_TAIL_MASK; - DELAY(1000); - } while (_head != _tail); - } + if (!pI830->noAccel) + (*pI830->AccelInfoRec->Sync)(pScrn); #ifndef BINDUNBIND #define BINDUNBIND 0 @@ -5018,30 +5261,27 @@ I830BIOSSaveScreen(ScreenPtr pScreen, int mode) I830Ptr pI830 = I830PTR(pScrn); Bool on = xf86IsUnblank(mode); CARD32 temp, ctrl, base; - int i; DPRINTF(PFX, "I830BIOSSaveScreen: %d, on is %s\n", mode, BOOLTOSTRING(on)); if (pScrn->vtSema) { - for (i = 0; i < pI830->availablePipes; i++) { - if (i == 0) { - ctrl = DSPACNTR; - base = DSPABASE; - } else { - ctrl = DSPBCNTR; - base = DSPBADDR; - } - if (pI830->planeEnabled[i]) { - temp = INREG(ctrl); - if (on) - temp |= DISPLAY_PLANE_ENABLE; - else - temp &= ~DISPLAY_PLANE_ENABLE; - OUTREG(ctrl, temp); - /* Flush changes */ - temp = INREG(base); - OUTREG(base, temp); - } + if (pI830->pipe == 0) { + ctrl = DSPACNTR; + base = DSPABASE; + } else { + ctrl = DSPBCNTR; + base = DSPBADDR; + } + if (pI830->planeEnabled[pI830->pipe]) { + temp = INREG(ctrl); + if (on) + temp |= DISPLAY_PLANE_ENABLE; + else + temp &= ~DISPLAY_PLANE_ENABLE; + OUTREG(ctrl, temp); + /* Flush changes */ + temp = INREG(base); + OUTREG(base, temp); } if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) { @@ -5134,6 +5374,10 @@ I830BIOSCloseScreen(int scrnIndex, ScreenPtr pScreen) I830BIOSLeaveVT(scrnIndex, 0); } + if (pI830->devicesTimer) + TimerCancel(pI830->devicesTimer); + pI830->devicesTimer = NULL; + DPRINTF(PFX, "\nUnmapping memory\n"); I830UnmapMem(pScrn); vgaHWUnmapMem(pScrn); @@ -5170,9 +5414,6 @@ I830BIOSCloseScreen(int scrnIndex, ScreenPtr pScreen) pI830->overlayOn = NULL; } - if (pI830->lidTimer) - TimerCancel(pI830->lidTimer); - pScrn->vtSema = FALSE; pI830->closing = FALSE; pScreen->CloseScreen = pI830->CloseScreen; @@ -5252,58 +5493,229 @@ I830PMEvent(int scrnIndex, pmEvent event, Bool undo) return TRUE; } +static int CountBits(int a) +{ + int i; + int b = 0; + + for (i=0;i<8;i++) { + if (a & (1<<i)) + b+=1; + } + + return b; +} + static CARD32 -I830LidTimer(OsTimerPtr timer, CARD32 now, pointer arg) +I830CheckDevicesTimer(OsTimerPtr timer, CARD32 now, pointer arg) { ScrnInfoPtr pScrn = (ScrnInfoPtr) arg; I830Ptr pI830 = I830PTR(pScrn); + int cloned = 0; if (pScrn->vtSema) { /* Check for monitor lid being closed/opened and act accordingly */ - int temp = INREG(SWF0) & 0x0000FFFF; + CARD32 adjust; + CARD32 temp = INREG(SWF0) & 0x0000FFFF; + int fixup = 0; + /* this avoids a BIOS call if possible */ 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 + I830Ptr pI8301; + I830Ptr pI8302 = NULL; + unsigned int toggle = GetToggleList(pScrn, 1); + + GetToggleList(pScrn, 2); + GetToggleList(pScrn, 3); + GetToggleList(pScrn, 4); + + if (IsPrimary(pScrn)) + pI8301 = pI830; + else + pI8301 = I830PTR(pI830->entityPrivate->pScrn_1); + + if (xf86IsEntityShared(pScrn->entityList[0])) + pI8302 = I830PTR(pI830->entityPrivate->pScrn_2); + + pI8301->lastDevice1 = pI8301->lastDevice2; + pI8301->lastDevice2 = pI8301->monitorSwitch; + + if (CountBits(temp & 0xff) > 1) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected cloned pipe mode (A).\n"); + if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) + temp = pI8301->MonType2 << 8 | pI8301->MonType1; + } else + if (CountBits((temp & 0xff00) >> 8) > 1) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected cloned pipe mode (B).\n"); + if (xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) + temp = pI8301->MonType2 << 8 | pI8301->MonType1; + } else + if (pI8301->lastDevice1 && pI8301->lastDevice2) { + if ( ((pI8301->lastDevice1 & 0xFF00) == 0) && + ((pI8301->lastDevice2 & 0x00FF) == 0) ) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected last devices (1).\n"); + cloned = 1; + } else if ( ((pI8301->lastDevice2 & 0xFF00) == 0) && + ((pI8301->lastDevice1 & 0x00FF) == 0) ) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected last devices (2).\n"); + cloned = 1; + } else + cloned = 0; } - /* 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"); + if (cloned && + ((CountBits(pI830->lastDevice1 & 0xff) > 1) || + ((CountBits((pI830->lastDevice1 & 0xff00) >> 8) > 1))) ) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected duplicate (1).\n"); + cloned = 0; + } else + if (cloned && + ((CountBits(pI830->lastDevice2 & 0xff) > 1) || + ((CountBits((pI830->lastDevice2 & 0xff00) >> 8) > 1))) ) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected duplicate (2).\n"); + cloned = 0; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Requested display devices 0x%lx.\n", temp); + + + /* If the BIOS doesn't flip between CRT, LFP and CRT+LFP we fake + * it here as it seems some just flip between CRT and LFP. Ugh! + * + * So this pushes them onto Pipe B and clones the displays, which + * is what most BIOS' should be doing. + * + * Cloned pipe mode should only be done when running single head. + */ + if (xf86IsEntityShared(pScrn->entityList[0])) + cloned = 0; + + if (cloned) { + if (pI830->Clone) + temp = pI8301->MonType2 << 8 | pI8301->MonType1; + else if (pI8301->lastDevice1 & 0xFF) + temp = pI8301->lastDevice1 << 8 | pI8301->lastDevice2; + else + temp = pI8301->lastDevice2 << 8 | pI8301->lastDevice1; + } + + /* Jump to our next mode if we detect we've been here before */ + if (temp == pI830->lastDevice1 || temp == pI830->lastDevice2) { + temp = toggle; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected duplicate devices. Toggling (0x%lx)\n", temp); } - pI830->monitorSwitch = conf; - + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected display change operation (0x%x, 0x%x, 0x%lx).\n", + pI8301->lastDevice1, pI8301->lastDevice2, temp); + + /* double check the display devices are what's configured and try + * not to do it twice because of dual heads with the code above */ + if (!SetDisplayDevices(pScrn, temp)) { + if ( cloned && + ((CountBits(temp & 0xff) > 1) || + (CountBits((temp & 0xff00) >> 8) > 1)) ) { + temp = pI8301->lastDevice2 | pI8301->lastDevice1; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Cloning failed, " + "trying dual pipe clone mode (0x%lx)\n", temp); + if (!SetDisplayDevices(pScrn, temp)) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to switch " + "to configured display devices (0x%lx).\n", temp); + else + pI830->Clone = TRUE; + } + } + pI8301->monitorSwitch = temp; + pI8301->operatingDevices = temp; + if (xf86IsEntityShared(pScrn->entityList[0])) { + pI8302->operatingDevices = temp; + pI8302->monitorSwitch = temp; + } + + fixup = 1; + } else { + int offset = pScrn->fbOffset + ((pScrn->frameY0 * pScrn->displayWidth + pScrn->frameX0) * pI830->cpp); + + if (pI830->pipe == 0) + adjust = INREG(DSPABASE); + else + adjust = INREG(DSPBBASE); + + if (adjust != offset) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Fixing display offsets.\n"); + + I830BIOSAdjustFrame(pScrn->pScreen->myNum, pScrn->frameX0, pScrn->frameY0, 0); + } + } + + if (fixup) { + ScreenPtr pCursorScreen; + int x = 0, y = 0; + + pCursorScreen = miPointerCurrentScreen(); + if (pScrn->pScreen == pCursorScreen) + miPointerPosition(&x, &y); + /* 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) + if (!(xf86IsEntityShared(pScrn->entityList[0]) || pI830->Clone) || cloned) { + if (temp & 0xFF00) pI830->pipe = 1; - } + else + pI830->pipe = 0; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Primary pipe is now %s.\n", pI830->pipe ? "B" : "A"); + } + 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; + if (xf86IsEntityShared(pScrn->entityList[0])) { + ScrnInfoPtr pScrn2; + I830Ptr pI8302; + + if (IsPrimary(pScrn)) { + pScrn2 = pI830->entityPrivate->pScrn_2; + pI8302 = I830PTR(pI830->entityPrivate->pScrn_2); + } else { + pScrn2 = pI830->entityPrivate->pScrn_1; + pI8302 = I830PTR(pI830->entityPrivate->pScrn_1); + } + + I830BIOSSwitchMode(pScrn2->pScreen->myNum, pScrn2->currentMode, 0); + I830BIOSAdjustFrame(pScrn2->pScreen->myNum, pScrn2->frameX0, pScrn2->frameY0, 0); + if (pScrn2->pScreen == pCursorScreen) { + int sigstate = xf86BlockSIGIO (); + miPointerWarpCursor(pScrn2->pScreen,x,y); + + /* xf86Info.currentScreen = pScrn->pScreen; */ + xf86UnblockSIGIO (sigstate); + if (pI8302->CursorInfoRec && !pI8302->SWCursor && pI8302->cursorOn) { + pI8302->CursorInfoRec->HideCursor(pScrn); + pI8302->CursorInfoRec->ShowCursor(pScrn); + pI8302->cursorOn = TRUE; + } + } + } + + if (pScrn->pScreen == pCursorScreen) { + int sigstate = xf86BlockSIGIO (); + miPointerWarpCursor(pScrn->pScreen,x,y); + + /* xf86Info.currentScreen = pScrn->pScreen; */ + xf86UnblockSIGIO (sigstate); + if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) { + pI830->CursorInfoRec->HideCursor(pScrn); + pI830->CursorInfoRec->ShowCursor(pScrn); + pI830->cursorOn = TRUE; + } } } } |