summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlan Hourihane <alanh@fairlite.demon.co.uk>2005-01-06 14:43:14 +0000
committerAlan Hourihane <alanh@fairlite.demon.co.uk>2005-01-06 14:43:14 +0000
commit076c5116ae5eda1822da70184cbcc8942b470541 (patch)
treeee07fbc884b3374284d12a7dbf7c3b30a7cb0413 /src
parentedb9b6fde0948bb1121a8456500ef9f55f734376 (diff)
Add:
- Intel i915GM support to 2D DDX and 3D Mesa drivers. - PanelID identification - DRI suspend/resume support - Detection of monitor changes on VT switches - Support custom video modes if available in the Video BIOS - 3D enhancements: * GL_ARB_texture_cube_map * GL_EXT_blend_equation_separate * GL_ATI_blend_equation_separate * GL_ARB_point_parameters * GL_NV_blend_square * GL_EXT_cull_vertex * GL_ARB_depth_texture * GL_SGIX_depth_texture * GL_ARB_shadow * GL_EXT_shadow_funcs * GL_3DFX_texture_compression_FXT1 By Tungsten Graphics, Keith Whitwell & Alan Hourihane.
Diffstat (limited to 'src')
-rw-r--r--src/common.h8
-rw-r--r--src/i810_driver.c4
-rw-r--r--src/i830.h6
-rw-r--r--src/i830_common.h3
-rw-r--r--src/i830_cursor.c2
-rw-r--r--src/i830_dri.c58
-rw-r--r--src/i830_driver.c525
-rw-r--r--src/i830_memory.c8
-rw-r--r--src/i830_modes.c712
-rw-r--r--src/i830_video.c80
10 files changed, 1317 insertions, 89 deletions
diff --git a/src/common.h b/src/common.h
index 961da215..62854455 100644
--- a/src/common.h
+++ b/src/common.h
@@ -305,6 +305,11 @@ extern int I810_DEBUG;
#define PCI_CHIP_I915_G_BRIDGE 0x2580
#endif
+#ifndef PCI_CHIP_I915_GM
+#define PCI_CHIP_I915_GM 0x2592
+#define PCI_CHIP_I915_GM_BRIDGE 0x2590
+#endif
+
#define IS_I810(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I810 || \
pI810->PciInfo->chipType == PCI_CHIP_I810_DC100 || \
pI810->PciInfo->chipType == PCI_CHIP_I810_E)
@@ -314,8 +319,9 @@ extern int I810_DEBUG;
#define IS_I85X(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I855_GM)
#define IS_I865G(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I865_G)
#define IS_I915G(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I915_G)
+#define IS_I915GM(pI810) (pI810->PciInfo->chipType == PCI_CHIP_I915_GM)
-#define IS_MOBILE(pI810) (IS_I830(pI810) || IS_I85X(pI810))
+#define IS_MOBILE(pI810) (IS_I830(pI810) || IS_I85X(pI810) || IS_I915GM(pI810))
#define GTT_PAGE_SIZE KB(4)
#define ROUND_TO(x, y) (((x) + (y) - 1) / (y) * (y))
diff --git a/src/i810_driver.c b/src/i810_driver.c
index b4732951..f60f7609 100644
--- a/src/i810_driver.c
+++ b/src/i810_driver.c
@@ -129,6 +129,7 @@ static SymTabRec I810Chipsets[] = {
{PCI_CHIP_I855_GM, "852GM/855GM"},
{PCI_CHIP_I865_G, "865G"},
{PCI_CHIP_I915_G, "915G"},
+ {PCI_CHIP_I915_GM, "915GM"},
{-1, NULL}
};
@@ -144,6 +145,7 @@ static PciChipsets I810PciChipsets[] = {
{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},
+ {PCI_CHIP_I915_GM, PCI_CHIP_I915_GM, RES_SHARED_VGA},
{-1, -1, RES_UNDEFINED }
};
@@ -560,6 +562,7 @@ I810Probe(DriverPtr drv, int flags)
case PCI_CHIP_I830_M:
case PCI_CHIP_I855_GM:
case PCI_CHIP_I915_G:
+ case PCI_CHIP_I915_GM:
xf86SetEntitySharable(usedChips[i]);
/* Allocate an entity private if necessary */
@@ -1805,7 +1808,6 @@ I810ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
vgaHWPtr hwp;
I810Ptr pI810;
- vgaRegPtr pVga;
hwp = VGAHWPTR(pScrn);
pI810 = I810PTR(pScrn);
diff --git a/src/i830.h b/src/i830.h
index 0cf3af93..6c153fa3 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -390,6 +390,7 @@ extern Bool I830Allocate3DMemory(ScrnInfoPtr pScrn, const int flags);
extern void I830SetupMemoryTiling(ScrnInfoPtr pScrn);
extern Bool I830DRIScreenInit(ScreenPtr pScreen);
extern Bool I830DRIDoMappings(ScreenPtr pScreen);
+extern Bool I830DRIResume(ScreenPtr pScreen);
extern void I830DRICloseScreen(ScreenPtr pScreen);
extern Bool I830DRIFinishScreenInit(ScreenPtr pScreen);
#endif
@@ -423,6 +424,11 @@ extern void I830ReadAllRegisters(I830Ptr pI830, I830RegPtr i830Reg);
extern void I830ChangeFrontbuffer(ScrnInfoPtr pScrn,int buffer);
+extern DisplayModePtr i830GetModePool(ScrnInfoPtr pScrn, vbeInfoPtr pVbe,
+ VbeInfoBlock *vbe, int modeTypes);
+extern void i830SetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe);
+extern void i830PrintModes(ScrnInfoPtr pScrn);
+
/*
* 12288 is set as the maximum, chosen because it is enough for
* 1920x1440@32bpp with a 2048 pixel line pitch with some to spare.
diff --git a/src/i830_common.h b/src/i830_common.h
index c5167c11..a0a00ff4 100644
--- a/src/i830_common.h
+++ b/src/i830_common.h
@@ -55,7 +55,8 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
typedef struct {
enum {
I830_INIT_DMA = 0x01,
- I830_CLEANUP_DMA = 0x02
+ I830_CLEANUP_DMA = 0x02,
+ I830_RESUME_DMA = 0x03
} func;
unsigned int mmio_offset;
int sarea_priv_offset;
diff --git a/src/i830_cursor.c b/src/i830_cursor.c
index c5fe2b88..367aaf45 100644
--- a/src/i830_cursor.c
+++ b/src/i830_cursor.c
@@ -304,7 +304,7 @@ I830SetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
}
/* have to upload the base for the new position */
- if (IS_I915G(pI830)) {
+ if (IS_I915G(pI830) || IS_I915GM(pI830)) {
if (pI830->CursorIsARGB)
OUTREG(CURSOR_A_BASE, pI830->CursorMemARGB->Physical);
else
diff --git a/src/i830_dri.c b/src/i830_dri.c
index 25ce9a97..034b0960 100644
--- a/src/i830_dri.c
+++ b/src/i830_dri.c
@@ -163,6 +163,24 @@ I830InitDma(ScrnInfoPtr pScrn)
}
static Bool
+I830ResumeDma(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ drmI830Init info;
+
+ memset(&info, 0, sizeof(drmI830Init));
+ info.func = I830_RESUME_DMA;
+
+ if (drmCommandWrite(pI830->drmSubFD, DRM_I830_INIT,
+ &info, sizeof(drmI830Init))) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "I830 Dma Resume Failed\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static Bool
I830SetParam(ScrnInfoPtr pScrn, int param, int value)
{
I830Ptr pI830 = I830PTR(pScrn);
@@ -510,7 +528,7 @@ I830DRIScreenInit(ScreenPtr pScreen)
return FALSE;
}
- /* Check the i830 DRM versioning */
+ /* Check the i915 DRM versioning */
{
drmVersionPtr version;
@@ -568,6 +586,9 @@ I830DRIScreenInit(ScreenPtr pScreen)
drmFreeVersion(version);
return FALSE;
}
+ if (version->version_minor < 2)
+ xf86DrvMsg(pScreen->myNum, X_WARNING,
+ "Resume functionality not available with DRM < 1.2\n");
pI830->drmMinor = version->version_minor;
drmFreeVersion(version);
}
@@ -742,6 +763,41 @@ I830DRIDoMappings(ScreenPtr pScreen)
return TRUE;
}
+Bool
+I830DRIResume(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ I830Ptr pI830 = I830PTR(pScrn);
+ I830DRIPtr pI830DRI = (I830DRIPtr) pI830->pDRIInfo->devPrivate;
+
+ DPRINTF(PFX, "I830DRIResume\n");
+
+ I830ResumeDma(pScrn);
+
+ {
+ pI830DRI->irq = drmGetInterruptFromBusID(pI830->drmSubFD,
+ ((pciConfigPtr) pI830->
+ PciInfo->thisCard)->busnum,
+ ((pciConfigPtr) pI830->
+ PciInfo->thisCard)->devnum,
+ ((pciConfigPtr) pI830->
+ PciInfo->thisCard)->funcnum);
+
+ if (drmCtlInstHandler(pI830->drmSubFD, pI830DRI->irq)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "[drm] failure adding irq handler\n");
+ pI830DRI->irq = 0;
+ return FALSE;
+ }
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "[drm] dma control initialized, using IRQ %d\n",
+ pI830DRI->irq);
+ }
+
+ return FALSE;
+}
+
void
I830DRICloseScreen(ScreenPtr pScreen)
{
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 7ed65147..a8b27dff 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -185,6 +185,7 @@ static SymTabRec I830BIOSChipsets[] = {
{PCI_CHIP_I855_GM, "852GM/855GM"},
{PCI_CHIP_I865_G, "865G"},
{PCI_CHIP_I915_G, "915G"},
+ {PCI_CHIP_I915_GM, "915GM"},
{-1, NULL}
};
@@ -194,6 +195,7 @@ static PciChipsets I830BIOSPciChipsets[] = {
{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},
+ {PCI_CHIP_I915_GM, PCI_CHIP_I915_GM, RES_SHARED_VGA},
{-1, -1, RES_UNDEFINED}
};
@@ -429,6 +431,114 @@ GetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh, int *availRefresh)
}
#endif
+struct panelid {
+ short hsize;
+ short vsize;
+ short fptype;
+ char redbpp;
+ char greenbpp;
+ char bluebpp;
+ char reservedbpp;
+ int rsvdoffscrnmemsize;
+ int rsvdoffscrnmemptr;
+ char reserved[14];
+};
+
+static void
+I830InterpretPanelID(int scrnIndex, unsigned char *tmp)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ struct panelid *block = (struct panelid *)tmp;
+
+#define PANEL_DEFAULT_HZ 60
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "PanelID returned panel resolution : %dx%d\n",
+ block->hsize, block->vsize);
+
+ /* If we get bogus values from this, don't accept it */
+ if (block->hsize == 0 || block->vsize == 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Bad Panel resolution - ignoring panelID\n");
+
+ return;
+ }
+
+ /* If we have monitor timings then don't overwrite them */
+ if (pScrn->monitor->nHsync > 0 &&
+ pScrn->monitor->nVrefresh > 0)
+ return;
+
+ /* With panels, we're always assuming a refresh of 60Hz */
+
+ pScrn->monitor->nHsync = 1;
+ pScrn->monitor->nVrefresh = 1;
+
+ /* Give a little tolerance for the selected panel */
+ pScrn->monitor->hsync[0].lo = (float)((PANEL_DEFAULT_HZ/1.05)*block->vsize)/1000;
+ pScrn->monitor->hsync[0].hi = (float)((PANEL_DEFAULT_HZ/0.95)*block->vsize)/1000;
+ pScrn->monitor->vrefresh[0].lo = (float)PANEL_DEFAULT_HZ;
+ pScrn->monitor->vrefresh[0].hi = (float)PANEL_DEFAULT_HZ;
+}
+
+/* This should probably go into the VBE layer */
+static unsigned char *
+vbeReadPanelID(vbeInfoPtr pVbe)
+{
+ int RealOff = pVbe->real_mode_base;
+ pointer page = pVbe->memory;
+ unsigned char *tmp = NULL;
+ int screen = pVbe->pInt10->scrnIndex;
+
+ pVbe->pInt10->ax = 0x4F11;
+ pVbe->pInt10->bx = 0x01;
+ pVbe->pInt10->cx = 0;
+ pVbe->pInt10->dx = 0;
+ pVbe->pInt10->es = SEG_ADDR(RealOff);
+ pVbe->pInt10->di = SEG_OFF(RealOff);
+ pVbe->pInt10->num = 0x10;
+
+ xf86ExecX86int10(pVbe->pInt10);
+
+ if ((pVbe->pInt10->ax & 0xff) != 0x4f) {
+ xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID invalid\n");
+ goto error;
+ }
+ switch (pVbe->pInt10->ax & 0xff00) {
+ case 0x0:
+ xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read successfully\n");
+ tmp = (unsigned char *)xnfalloc(32);
+ memcpy(tmp,page,32);
+ break;
+ case 0x100:
+ xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read failed\n");
+ break;
+ default:
+ xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID unknown failure %i\n",
+ pVbe->pInt10->ax & 0xff00);
+ break;
+ }
+
+ error:
+ return tmp;
+}
+
+static void
+vbeDoPanelID(vbeInfoPtr pVbe)
+{
+ unsigned char *PanelID_data;
+
+ if (!pVbe) return;
+
+ PanelID_data = vbeReadPanelID(pVbe);
+
+ if (!PanelID_data)
+ return;
+
+ I830InterpretPanelID(pVbe->pInt10->scrnIndex, PanelID_data);
+}
+
+
static int
SetRefreshRate(ScrnInfoPtr pScrn, int mode, int refresh)
{
@@ -650,12 +760,33 @@ SetDisplayDevices(ScrnInfoPtr pScrn, int devices)
temp = INREG(SWF0);
OUTREG(SWF0, (temp & ~(0xffff)) | (devices & 0xffff));
- if (GetDisplayDevices(pScrn) != devices)
+ /* 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.
+ */
+ temp = INREG(ADPA);
+ temp &= ~0xc0000c00;
+ /* Turn on ADPA */
+ if (devices & PIPE_CRT) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "BIOS call failed, turning ADPA on directly. Pipe A.\n");
+ temp |= 0x80000000;
+ }
+ if ((devices >> 8) & PIPE_CRT) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "BIOS call failed, turning ADPA on directly. Pipe B.\n");
+ temp |= 0xC0000000;
+ }
+ OUTREG(ADPA, temp);
+
+ 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;
+ }
- return FALSE;
+ return TRUE;
}
static Bool
@@ -915,9 +1046,10 @@ I830DetectDisplayDevice(ScrnInfoPtr pScrn)
/* Check for active devices connected to each display pipe. */
for (n = 0; n < pI830->availablePipes; n++) {
pipe = ((pI830->operatingDevices >> PIPE_SHIFT(n)) & PIPE_ACTIVE_MASK);
- if (pipe) {
+ if (pipe)
pI830->pipeEnabled[n] = TRUE;
- }
+ else
+ pI830->pipeEnabled[n] = FALSE;
}
GetPipeSizes(pScrn);
@@ -941,7 +1073,7 @@ I830DetectMemory(ScrnInfoPtr pScrn)
* 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)) {
+ if (IS_I85X(pI830) || IS_I865G(pI830) || IS_I915G(pI830) || IS_I915GM(pI830)) {
switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
case I855_GMCH_GMS_STOLEN_1M:
memsize = MB(1) - KB(range);
@@ -959,11 +1091,11 @@ I830DetectMemory(ScrnInfoPtr pScrn)
memsize = MB(32) - KB(range);
break;
case I915G_GMCH_GMS_STOLEN_48M:
- if (IS_I915G(pI830))
+ if (IS_I915G(pI830) || IS_I915GM(pI830))
memsize = MB(48) - KB(range);
break;
case I915G_GMCH_GMS_STOLEN_64M:
- if (IS_I915G(pI830))
+ if (IS_I915G(pI830) || IS_I915GM(pI830))
memsize = MB(64) - KB(range);
break;
}
@@ -1170,12 +1302,12 @@ SaveBIOSMemSize(ScrnInfoPtr pScrn)
* Original implementation by Christian Zietz in a stand-alone tool.
*/
static CARD32
-TweakMemorySize(ScrnInfoPtr pScrn, CARD32 newsize, Bool preinit)
+TweakMemorySize(ScrnInfoPtr pScrn, CARD32 newsize)
{
#define SIZE 0x10000
#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);
@@ -1185,13 +1317,11 @@ TweakMemorySize(ScrnInfoPtr pScrn, CARD32 newsize, Bool preinit)
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
- || !(IS_845G(pI830) || IS_I85X(pI830) || IS_I865G(pI830)))
+ int reg = (IS_845G(pI830) || IS_I865G(pI830)) ? _845_DRAM_RW_CONTROL : _855_DRAM_RW_CONTROL;
+
+ if(!pI830->PciInfo
+ || !(IS_845G(pI830) || IS_I85X(pI830) || IS_I865G(pI830)))
return 0;
if (!pI830->pVbe)
@@ -1201,7 +1331,8 @@ TweakMemorySize(ScrnInfoPtr pScrn, CARD32 newsize, Bool preinit)
pI830->pVbe->pInt10->BIOSseg << 4);
if (!pI830->BIOSMemSizeLoc) {
- if (!preinit)
+
+ if (!pI830->preinit)
return 0;
/* Search for MAGIC string */
@@ -1217,32 +1348,30 @@ TweakMemorySize(ScrnInfoPtr pScrn, CARD32 newsize, Bool preinit)
if (j < len) return 0;
pI830->BIOSMemSizeLoc = (i - j + 1 + (IS_845G(pI830)
- ? _845_IDOFFSET : _855_IDOFFSET));
+ ? _845_IDOFFSET : _855_IDOFFSET));
}
-
+
position = biosAddr + pI830->BIOSMemSizeLoc;
oldsize = *(CARD32 *)position;
-
ret = oldsize - 0x21000;
-
+
/* verify that register really contains current size */
- if (preinit && ((ret >> 16) != pI830->vbeInfo->TotalMemory))
+ if (pI830->preinit && ((ret >> 16) != pI830->vbeInfo->TotalMemory))
return 0;
oldpermission = pciReadLong(tag, reg);
pciWriteLong(tag, reg, DRAM_WRITE | (oldpermission & 0xffff));
-
- *(CARD32 *)position = newsize + 0x21000;
- if (preinit) {
+ *(CARD32 *)position = newsize + 0x21000;
+ if (pI830->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 != (newsize >> 16)){
+ if (pI830->vbeInfo->TotalMemory != (newsize >> 16)) {
ret = 0;
*(CARD32 *)position = oldsize;
} else {
@@ -1266,7 +1395,7 @@ RestoreBIOSMemSize(ScrnInfoPtr pScrn)
DPRINTF(PFX, "RestoreBIOSMemSize\n");
- if (TweakMemorySize(pScrn, pI830->saveBIOSMemSize,FALSE))
+ if (TweakMemorySize(pScrn, pI830->saveBIOSMemSize))
return;
if (!pI830->overrideBIOSMemSize)
@@ -1507,6 +1636,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
I830EntPtr pI830Ent = NULL;
int mem, memsize;
int flags24;
+ int defmon = 0;
int i, n;
char *s;
pointer pDDCModule, pVBEModule;
@@ -1659,6 +1789,9 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
case PCI_CHIP_I915_G:
chipname = "915G";
break;
+ case PCI_CHIP_I915_GM:
+ chipname = "915GM";
+ break;
default:
chipname = "unknown chipset";
break;
@@ -1696,7 +1829,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
pI830->LinearAddr = pI830->pEnt->device->MemBase;
from = X_CONFIG;
} else {
- if (IS_I915G(pI830)) {
+ if (IS_I915G(pI830) || IS_I915GM(pI830)) {
pI830->LinearAddr = pI830->PciInfo->memBase[2] & 0xF0000000;
from = X_PROBED;
} else if (pI830->PciInfo->memBase[1] != 0) {
@@ -1718,7 +1851,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
pI830->MMIOAddr = pI830->pEnt->device->IOBase;
from = X_CONFIG;
} else {
- if (IS_I915G(pI830)) {
+ if (IS_I915G(pI830) || IS_I915GM(pI830)) {
pI830->MMIOAddr = pI830->PciInfo->memBase[0] & 0xFFF80000;
from = X_PROBED;
} else if (pI830->PciInfo->memBase[1]) {
@@ -1763,7 +1896,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
pI830->FbMapSize = 0x4000000; /* 64MB - has this been tested ?? */
}
} else {
- if (IS_I915G(pI830)) {
+ if (IS_I915G(pI830) || IS_I915GM(pI830)) {
if (pI830->PciInfo->memBase[2] & 0x08000000)
pI830->FbMapSize = 0x8000000; /* 128MB aperture */
else
@@ -2122,13 +2255,14 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
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
+ if ((pI830->saveBIOSMemSize =
+ TweakMemorySize(pScrn, pI830->newBIOSMemSize)) != 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");
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "BIOS view of memory size can't be changed "
+ "(this is not an error).\n");
}
}
}
@@ -2372,7 +2506,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
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) || IS_I915G(pI830))
+ if (IS_845G(pI830) || IS_I85X(pI830) || IS_I865G(pI830) || IS_I915G(pI830) || IS_I915GM(pI830))
pI830->NeedRingBufferLow = TRUE;
/*
@@ -2412,12 +2546,22 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
"Maximum frambuffer space: %d kByte\n", pScrn->videoRam);
SetPipeAccess(pScrn);
+
if ((pDDCModule = xf86LoadSubModule(pScrn, "ddc")) == NULL) {
PreInitCleanup(pScrn);
return FALSE;
}
- if ((pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule)) != NULL) {
+ /* Check we are on pipe B and have an LFP connected, before trying to
+ * read PanelID information. */
+ if ((pI830->pipe == 1) && (pI830->operatingDevices & (PIPE_LFP << 8))) {
+ 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);
}
if ((pScrn->monitor->DDC = pI830->vesa->monitor) != NULL)
@@ -2484,7 +2628,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
}
}
- if (pI830->useExtendedRefresh) {
+ if (pI830->useExtendedRefresh && !pI830->vesa->useDefaultRefresh) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Will use BIOS call 0x5f05 to set refresh rates for CRTs.\n");
}
@@ -2500,12 +2644,37 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"Maximum space available for video modes: %d kByte\n", memsize);
+ /* By now, we should have had some monitor settings, but if not, we
+ * need to setup some defaults. These are used in common/xf86Modes.c
+ * so we'll use them here for GetModePool, and that's all.
+ * We unset them after the call, so we can report 'defaults' as being
+ * used through the common layer.
+ */
+#define DEFAULT_HSYNC_LO 28
+#define DEFAULT_HSYNC_HI 33
+#define DEFAULT_VREFRESH_LO 43
+#define DEFAULT_VREFRESH_HI 72
+
+ if (pScrn->monitor->nHsync == 0) {
+ pScrn->monitor->hsync[0].lo = DEFAULT_HSYNC_LO;
+ pScrn->monitor->hsync[0].hi = DEFAULT_HSYNC_HI;
+ pScrn->monitor->nHsync = 1;
+ defmon |= 1;
+ }
+
+ if (pScrn->monitor->nVrefresh == 0) {
+ pScrn->monitor->vrefresh[0].lo = DEFAULT_VREFRESH_LO;
+ pScrn->monitor->vrefresh[0].hi = DEFAULT_VREFRESH_HI;
+ pScrn->monitor->nVrefresh = 1;
+ defmon |= 2;
+ }
+
/*
* 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 for VBEGetModePool().
+ * V_MODETYPE_VGA in the flags.
*/
- pScrn->modePool = VBEGetModePool(pScrn, pI830->pVbe, pI830->vbeInfo,
+ pScrn->modePool = i830GetModePool(pScrn, pI830->pVbe, pI830->vbeInfo,
V_MODETYPE_VGA);
if (!pScrn->modePool) {
@@ -2515,6 +2684,21 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
return FALSE;
}
+ /* This may look a little weird, but to notify that we're using the
+ * default hsync/vrefresh we need to unset what we just set .....
+ */
+ if (defmon & 1) {
+ pScrn->monitor->hsync[0].lo = 0;
+ pScrn->monitor->hsync[0].hi = 0;
+ pScrn->monitor->nHsync = 0;
+ }
+
+ if (defmon & 2) {
+ pScrn->monitor->vrefresh[0].lo = 0;
+ pScrn->monitor->vrefresh[0].hi = 0;
+ pScrn->monitor->nVrefresh = 0;
+ }
+
SetPipeAccess(pScrn);
VBESetModeNames(pScrn->modePool);
@@ -2670,7 +2854,7 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
#endif
SetPipeAccess(pScrn);
- VBEPrintModes(pScrn);
+ i830PrintModes(pScrn);
if (!pI830->vesa->useDefaultRefresh) {
/*
@@ -2681,11 +2865,13 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
* if there are no non-CRT devices attached.
*/
SetPipeAccess(pScrn);
- VBESetModeParameters(pScrn, pI830->pVbe);
+ i830SetModeParameters(pScrn, pI830->pVbe);
}
/* PreInit shouldn't leave any state changes, so restore this. */
+ pI830->preinit = FALSE; /* temporarily do this */
RestoreBIOSMemSize(pScrn);
+ pI830->preinit = TRUE; /* now put it back */
/* Don't need MMIO access anymore. */
if (pI830->swfSaved) {
@@ -3153,10 +3339,10 @@ I830VESASetVBEMode(ScrnInfoPtr pScrn, int mode, VbeCRTCInfoBlock * block)
VbeCRTCInfoBlock newblock;
int Mon;
- if (!pI830->pipe)
- Mon = pI830->MonType2;
- else
+ if (pI830->pipe == 0)
Mon = pI830->MonType1;
+ else
+ Mon = pI830->MonType2;
SetBIOSPipe(pScrn, !pI830->pipe);
@@ -3306,10 +3492,10 @@ I830VESASetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
*/
if (pI830->Clone) {
int Mon;
- if (!pI830->pipe)
- Mon = pI830->MonType2;
- else
+ 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 &&
@@ -3938,7 +4124,7 @@ I830BIOSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
* first, then re-initialise the VBE information.
*/
pI830->pVbe = VBEInit(NULL, pI830->pEnt->index);
- if (!TweakMemorySize(pScrn, pI830->newBIOSMemSize,FALSE))
+ if (!TweakMemorySize(pScrn, pI830->newBIOSMemSize))
SetBIOSMemSize(pScrn, pI830->newBIOSMemSize);
if (!pI830->pVbe)
return FALSE;
@@ -4346,6 +4532,8 @@ I830BIOSLeaveVT(int scrnIndex, int flags)
DPRINTF(PFX, "calling dri lock\n");
DRILock(screenInfo.screens[scrnIndex], 0);
pI830->LockHeld = 1;
+
+ drmCtlUninstHandler(pI830->drmSubFD);
}
#endif
@@ -4361,6 +4549,7 @@ I830BIOSLeaveVT(int scrnIndex, int flags)
I830UnbindGARTMemory(pScrn);
if (pI830->AccelInfoRec)
pI830->AccelInfoRec->NeedToSync = FALSE;
+
if (IsPrimary(pScrn)) {
if (!SetDisplayDevices(pScrn, pI830->savedDevices)) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
@@ -4373,6 +4562,201 @@ I830BIOSLeaveVT(int scrnIndex, int flags)
}
}
+static Bool
+I830DetectMonitorChange(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ pointer pDDCModule;
+ DisplayModePtr p, pMon;
+ xf86MonPtr DDC;
+ struct detailed_monitor_section* detMon;
+ int i, memsize;
+ struct monitor_ranges *mon_range = NULL;
+ int displayWidth = pScrn->displayWidth;
+ int curHDisplay = pScrn->currentMode->HDisplay;
+ int curVDisplay = pScrn->currentMode->VDisplay;
+
+ DPRINTF(PFX, "Detect Monitor Change\n");
+
+ SetPipeAccess(pScrn);
+
+ /* Re-read EDID */
+ if ((pDDCModule = xf86LoadSubModule(pScrn, "ddc")) == NULL)
+ return FALSE;
+ if (pI830->vesa->monitor)
+ xfree(pI830->vesa->monitor);
+ if ((pI830->vesa->monitor = vbeDoEDID(pI830->pVbe, pDDCModule)) != NULL)
+ xf86PrintEDID(pI830->vesa->monitor);
+ xf86UnloadSubModule(pDDCModule);
+ if ((pScrn->monitor->DDC = pI830->vesa->monitor) != NULL)
+ xf86SetDDCproperties(pScrn, pI830->vesa->monitor);
+ else
+ /* No DDC, so get out of here, and continue to use the current settings */
+ return FALSE;
+
+ DDC = (xf86MonPtr)(pScrn->monitor->DDC);
+
+ /* Now change the hsync/vrefresh values of the current monitor to
+ * match those of DDC */
+ for (i = 0; i < 4; i++) {
+ detMon = &DDC->det_mon[i];
+ if(detMon->type == DS_RANGES)
+ mon_range = &detMon->section.ranges;
+ }
+
+ 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 */
+
+ if (mon_range) {
+#define DDC_SYNC_TOLERANCE SYNC_TOLERANCE
+ if (pScrn->monitor->nHsync > 0) {
+ for (i = 0; i < pScrn->monitor->nHsync; i++) {
+ if ((1.0 - DDC_SYNC_TOLERANCE) * mon_range->min_h >
+ pScrn->monitor->hsync[i].lo ||
+ (1.0 + DDC_SYNC_TOLERANCE) * mon_range->max_h <
+ pScrn->monitor->hsync[i].hi) {
+ 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,
+ mon_range->min_h, mon_range->max_h);
+ }
+ pScrn->monitor->hsync[i].lo = mon_range->min_h;
+ pScrn->monitor->hsync[i].hi = mon_range->max_h;
+ }
+ }
+
+ if (pScrn->monitor->nVrefresh > 0) {
+ for (i=0; i<pScrn->monitor->nVrefresh; i++) {
+ if ((1.0 - DDC_SYNC_TOLERANCE) * mon_range->min_v >
+ pScrn->monitor->vrefresh[i].lo ||
+ (1.0 + DDC_SYNC_TOLERANCE) * mon_range->max_v <
+ pScrn->monitor->vrefresh[i].hi) {
+ 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,
+ mon_range->min_v, mon_range->max_v);
+ }
+ pScrn->monitor->vrefresh[i].lo = mon_range->min_v;
+ pScrn->monitor->vrefresh[i].hi = mon_range->max_v;
+ }
+ }
+ } /* if (mon_range) */
+
+ /* Revalidate the modes */
+
+ /*
+ * 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.
+ */
+ pScrn->modePool = i830GetModePool(pScrn, pI830->pVbe, pI830->vbeInfo,
+ V_MODETYPE_VGA);
+
+ if (!pScrn->modePool) {
+ /* This is bad, which would cause the Xserver to exit, maybe
+ * we should default to a 640x480 @ 60Hz mode here ??? */
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "No Video BIOS modes for chosen depth.\n");
+ return FALSE;
+ }
+
+ SetPipeAccess(pScrn);
+ VBESetModeNames(pScrn->modePool);
+
+ if (pScrn->videoRam > (pI830->vbeInfo->TotalMemory * 64))
+ memsize = pI830->vbeInfo->TotalMemory * 64;
+ else
+ memsize = pScrn->videoRam;
+
+ VBEValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes, NULL,
+ NULL, 0, MAX_DISPLAY_PITCH, 1,
+ 0, MAX_DISPLAY_HEIGHT,
+ pScrn->display->virtualX,
+ pScrn->display->virtualY,
+ memsize, LOOKUP_BEST_REFRESH);
+
+ p = pScrn->modes;
+ if (p == NULL)
+ return FALSE;
+ do {
+ int Clock = 100000000; /* incredible value */
+
+ for (pMon = pScrn->monitor->Modes; pMon != NULL; pMon = pMon->next) {
+ if ((pMon->HDisplay != p->HDisplay) ||
+ (pMon->VDisplay != p->VDisplay) ||
+ (pMon->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2)))
+ continue;
+
+ /* Find lowest supported Clock for this resolution */
+ if (Clock > pMon->Clock)
+ Clock = pMon->Clock;
+ }
+
+ if (mon_range->max_clock < 2550 &&
+ Clock / 1000.0 > mon_range->max_clock) {
+#if 0
+ ErrorF("(%s,%s) mode clock %gMHz exceeds DDC maximum %dMHz\n",
+ p->name, pScrn->monitor->id,
+ Clock/1000.0, mon_range->max_clock);
+#endif
+ p->status = MODE_BAD;
+ }
+ p = p->next;
+ } while (p != NULL && p != pScrn->modes);
+
+ pScrn->displayWidth = displayWidth; /* restore old displayWidth */
+
+ xf86PruneDriverModes(pScrn);
+ i830PrintModes(pScrn);
+
+ /* Now check if the previously used mode is o.k. for the current monitor.
+ * This allows VT switching to continue happily when not disconnecting
+ * and reconnecting monitors */
+
+ pScrn->currentMode = pScrn->modes;
+ p = pScrn->modes;
+ if (p == NULL)
+ return FALSE;
+ do {
+ if ((p->HDisplay == curHDisplay) &&
+ (p->VDisplay == curVDisplay) &&
+ (!(p->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2)))) {
+ pScrn->currentMode = p; /* previous mode is o.k. */
+ }
+ p = p->next;
+ } while (p != NULL && p != pScrn->modes);
+
+ /* Now readjust for panning if necessary */
+ {
+ pScrn->frameX0 = (pScrn->frameX0 + pScrn->frameX1 + 1 - pScrn->currentMode->HDisplay) / 2;
+
+ if (pScrn->frameX0 < 0)
+ pScrn->frameX0 = 0;
+
+ pScrn->frameX1 = pScrn->frameX0 + pScrn->currentMode->HDisplay - 1;
+ if (pScrn->frameX1 >= pScrn->virtualX) {
+ pScrn->frameX0 = pScrn->virtualX - pScrn->currentMode->HDisplay;
+ pScrn->frameX1 = pScrn->virtualX - 1;
+ }
+
+ pScrn->frameY0 = (pScrn->frameY0 + pScrn->frameY1 + 1 - pScrn->currentMode->VDisplay) / 2;
+
+ if (pScrn->frameY0 < 0)
+ pScrn->frameY0 = 0;
+
+ pScrn->frameY1 = pScrn->frameY0 + pScrn->currentMode->VDisplay - 1;
+ if (pScrn->frameY1 >= pScrn->virtualY) {
+ pScrn->frameY0 = pScrn->virtualY - pScrn->currentMode->VDisplay;
+ pScrn->frameY1 = pScrn->virtualY - 1;
+ }
+ }
+
+ return TRUE;
+}
+
/*
* This gets called when gaining control of the VT, and from ScreenInit().
*/
@@ -4385,10 +4769,36 @@ I830BIOSEnterVT(int scrnIndex, int flags)
DPRINTF(PFX, "Enter VT\n");
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,
+ * we'll warm boot it.
+ */
if (!SetDisplayDevices(pScrn, pI830->operatingDevices)) {
- xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ xf86Int10InfoPtr pInt = xf86InitInt10(pI830->pEnt->index);
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "SetDisplayDevices failed, re-trying.\n");
+
+ /* Now perform our warm boot */
+ if (pInt) {
+ pInt->num = 0xe6;
+ xf86ExecX86int10 (pInt);
+ xf86FreeInt10 (pInt);
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Re-POSTing via int10.\n");
+ } else {
+ 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,
"Failed to switch to configured display devices\n");
- return FALSE;
+ return FALSE;
+ }
}
}
@@ -4400,7 +4810,7 @@ I830BIOSEnterVT(int scrnIndex, int flags)
return FALSE;
CheckInheritedState(pScrn);
- if (!TweakMemorySize(pScrn, pI830->newBIOSMemSize,FALSE))
+ if (!TweakMemorySize(pScrn, pI830->newBIOSMemSize))
SetBIOSMemSize(pScrn, pI830->newBIOSMemSize);
/*
@@ -4420,8 +4830,13 @@ I830BIOSEnterVT(int scrnIndex, int flags)
pScrn->virtualY * pScrn->displayWidth * pI830->cpp);
#endif
+ /* Detect monitor change and switch to suitable mode */
+ if (!pI830->starting)
+ I830DetectMonitorChange(pScrn);
+
if (!I830VESASetMode(pScrn, pScrn->currentMode))
return FALSE;
+
#ifdef I830_XV
I830VideoSwitchModeAfter(pScrn, pScrn->currentMode);
#endif
@@ -4438,6 +4853,10 @@ I830BIOSEnterVT(int scrnIndex, int flags)
#ifdef XF86DRI
if (pI830->directRenderingEnabled) {
if (!pI830->starting) {
+ /* gdg DRM driver 1.2 supports resume */
+ if (pI830->drmMinor >= 2)
+ I830DRIResume(screenInfo.screens[scrnIndex]);
+
I830EmitInvarientState(pScrn);
I830RefreshRing(pScrn);
I830Sync(pScrn);
diff --git a/src/i830_memory.c b/src/i830_memory.c
index aad103a8..15de1806 100644
--- a/src/i830_memory.c
+++ b/src/i830_memory.c
@@ -1236,7 +1236,7 @@ SetFence(ScrnInfoPtr pScrn, int nr, unsigned int start, unsigned int pitch,
i830Reg->Fence[nr] = 0;
- if (IS_I915G(pI830))
+ if (IS_I915G(pI830) || IS_I915GM(pI830))
fence_mask = ~I915G_FENCE_START_MASK;
else
fence_mask = ~I830_FENCE_START_MASK;
@@ -1244,7 +1244,7 @@ SetFence(ScrnInfoPtr pScrn, int nr, unsigned int start, unsigned int pitch,
if (start & fence_mask) {
xf86DrvMsg(X_WARNING, pScrn->scrnIndex,
"SetFence: %d: start (0x%08x) is not %s aligned\n",
- nr, start, (IS_I915G(pI830)) ? "1MB" : "512k");
+ nr, start, (IS_I915G(pI830) || IS_I915GM(pI830)) ? "1MB" : "512k");
return;
}
@@ -1264,7 +1264,7 @@ SetFence(ScrnInfoPtr pScrn, int nr, unsigned int start, unsigned int pitch,
val = (start | FENCE_X_MAJOR | FENCE_VALID);
- if (IS_I915G(pI830)) {
+ if (IS_I915G(pI830) || IS_I915GM(pI830)) {
switch (size) {
case MB(1):
val |= I915G_FENCE_SIZE_1M;
@@ -1325,7 +1325,7 @@ SetFence(ScrnInfoPtr pScrn, int nr, unsigned int start, unsigned int pitch,
}
}
- if (IS_I915G(pI830))
+ if (IS_I915G(pI830) || IS_I915GM(pI830))
fence_pitch = pitch / 512;
else
fence_pitch = pitch / 128;
diff --git a/src/i830_modes.c b/src/i830_modes.c
new file mode 100644
index 00000000..853683df
--- /dev/null
+++ b/src/i830_modes.c
@@ -0,0 +1,712 @@
+#define DEBUG_VERB 2
+/*
+ * Copyright © 2002 David Dawes
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the author(s) shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization from
+ * the author(s).
+ *
+ * Authors: David Dawes <dawes@xfree86.org>
+ *
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/vbe/vbeModes.c,v 1.6 2002/11/02 01:38:25 dawes Exp $
+ */
+/*
+ * Modified by Alan Hourihane <alanh@tungstengraphics.com>
+ * to support extended BIOS modes for the Intel chipsets
+ */
+
+#include "xf86.h"
+#include "xf86_ansic.h"
+#include "vbe.h"
+#include "vbeModes.h"
+#include "i830.h"
+
+#include <math.h>
+
+#define rint(x) floor(x)
+
+#define MARGIN_PERCENT 1.8 /* % of active vertical image */
+#define CELL_GRAN 8.0 /* assumed character cell granularity */
+#define MIN_PORCH 1 /* minimum front porch */
+#define V_SYNC_RQD 3 /* width of vsync in lines */
+#define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */
+#define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */
+#define M 600.0 /* blanking formula gradient */
+#define C 40.0 /* blanking formula offset */
+#define K 128.0 /* blanking formula scaling factor */
+#define J 20.0 /* blanking formula scaling factor */
+
+/* C' and M' are part of the Blanking Duty Cycle computation */
+
+#define C_PRIME (((C - J) * K/256.0) + J)
+#define M_PRIME (K/256.0 * M)
+
+static DisplayModePtr
+i830GetGTF (int h_pixels, int v_lines, float freq,
+ int interlaced, int margins)
+{
+ float h_pixels_rnd;
+ float v_lines_rnd;
+ float v_field_rate_rqd;
+ float top_margin;
+ float bottom_margin;
+ float interlace;
+ float h_period_est;
+ float vsync_plus_bp;
+ float v_back_porch;
+ float total_v_lines;
+ float v_field_rate_est;
+ float h_period;
+ float v_field_rate;
+ float v_frame_rate;
+ float left_margin;
+ float right_margin;
+ float total_active_pixels;
+ float ideal_duty_cycle;
+ float h_blank;
+ float total_pixels;
+ float pixel_freq;
+ float h_freq;
+
+ float h_sync;
+ float h_front_porch;
+ float v_odd_front_porch_lines;
+ DisplayModePtr m;
+
+ m = xnfcalloc(sizeof(DisplayModeRec), 1);
+
+
+ /* 1. In order to give correct results, the number of horizontal
+ * pixels requested is first processed to ensure that it is divisible
+ * by the character size, by rounding it to the nearest character
+ * cell boundary:
+ *
+ * [H PIXELS RND] = ((ROUND([H PIXELS]/[CELL GRAN RND],0))*[CELLGRAN RND])
+ */
+
+ h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN;
+
+
+ /* 2. If interlace is requested, the number of vertical lines assumed
+ * by the calculation must be halved, as the computation calculates
+ * the number of vertical lines per field. In either case, the
+ * number of lines is rounded to the nearest integer.
+ *
+ * [V LINES RND] = IF([INT RQD?]="y", ROUND([V LINES]/2,0),
+ * ROUND([V LINES],0))
+ */
+
+ v_lines_rnd = interlaced ?
+ rint((float) v_lines) / 2.0 :
+ rint((float) v_lines);
+
+ /* 3. Find the frame rate required:
+ *
+ * [V FIELD RATE RQD] = IF([INT RQD?]="y", [I/P FREQ RQD]*2,
+ * [I/P FREQ RQD])
+ */
+
+ v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq);
+
+ /* 4. Find number of lines in Top margin:
+ *
+ * [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y",
+ * ROUND(([MARGIN%]/100*[V LINES RND]),0),
+ * 0)
+ */
+
+ top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
+
+ /* 5. Find number of lines in Bottom margin:
+ *
+ * [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y",
+ * ROUND(([MARGIN%]/100*[V LINES RND]),0),
+ * 0)
+ */
+
+ bottom_margin = margins ? rint(MARGIN_PERCENT/100.0 * v_lines_rnd) : (0.0);
+
+ /* 6. If interlace is required, then set variable [INTERLACE]=0.5:
+ *
+ * [INTERLACE]=(IF([INT RQD?]="y",0.5,0))
+ */
+
+ interlace = interlaced ? 0.5 : 0.0;
+
+ /* 7. Estimate the Horizontal period
+ *
+ * [H PERIOD EST] = ((1/[V FIELD RATE RQD]) - [MIN VSYNC+BP]/1000000) /
+ * ([V LINES RND] + (2*[TOP MARGIN (LINES)]) +
+ * [MIN PORCH RND]+[INTERLACE]) * 1000000
+ */
+
+ h_period_est = (((1.0/v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP/1000000.0))
+ / (v_lines_rnd + (2*top_margin) + MIN_PORCH + interlace)
+ * 1000000.0);
+
+ /* 8. Find the number of lines in V sync + back porch:
+ *
+ * [V SYNC+BP] = ROUND(([MIN VSYNC+BP]/[H PERIOD EST]),0)
+ */
+
+ vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP/h_period_est);
+
+ /* 9. Find the number of lines in V back porch alone:
+ *
+ * [V BACK PORCH] = [V SYNC+BP] - [V SYNC RND]
+ *
+ * XXX is "[V SYNC RND]" a typo? should be [V SYNC RQD]?
+ */
+
+ v_back_porch = vsync_plus_bp - V_SYNC_RQD;
+
+ /* 10. Find the total number of lines in Vertical field period:
+ *
+ * [TOTAL V LINES] = [V LINES RND] + [TOP MARGIN (LINES)] +
+ * [BOT MARGIN (LINES)] + [V SYNC+BP] + [INTERLACE] +
+ * [MIN PORCH RND]
+ */
+
+ total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp +
+ interlace + MIN_PORCH;
+
+ /* 11. Estimate the Vertical field frequency:
+ *
+ * [V FIELD RATE EST] = 1 / [H PERIOD EST] / [TOTAL V LINES] * 1000000
+ */
+
+ v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
+
+ /* 12. Find the actual horizontal period:
+ *
+ * [H PERIOD] = [H PERIOD EST] / ([V FIELD RATE RQD] / [V FIELD RATE EST])
+ */
+
+ h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
+
+ /* 13. Find the actual Vertical field frequency:
+ *
+ * [V FIELD RATE] = 1 / [H PERIOD] / [TOTAL V LINES] * 1000000
+ */
+
+ v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0;
+
+ /* 14. Find the Vertical frame frequency:
+ *
+ * [V FRAME RATE] = (IF([INT RQD?]="y", [V FIELD RATE]/2, [V FIELD RATE]))
+ */
+
+ v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate;
+
+ /* 15. Find number of pixels in left margin:
+ *
+ * [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y",
+ * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 /
+ * [CELL GRAN RND]),0)) * [CELL GRAN RND],
+ * 0))
+ */
+
+ left_margin = margins ?
+ rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN :
+ 0.0;
+
+ /* 16. Find number of pixels in right margin:
+ *
+ * [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y",
+ * (ROUND( ([H PIXELS RND] * [MARGIN%] / 100 /
+ * [CELL GRAN RND]),0)) * [CELL GRAN RND],
+ * 0))
+ */
+
+ right_margin = margins ?
+ rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN :
+ 0.0;
+
+ /* 17. Find total number of active pixels in image and left and right
+ * margins:
+ *
+ * [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] +
+ * [RIGHT MARGIN (PIXELS)]
+ */
+
+ total_active_pixels = h_pixels_rnd + left_margin + right_margin;
+
+ /* 18. Find the ideal blanking duty cycle from the blanking duty cycle
+ * equation:
+ *
+ * [IDEAL DUTY CYCLE] = [C'] - ([M']*[H PERIOD]/1000)
+ */
+
+ ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0);
+
+ /* 19. Find the number of pixels in the blanking time to the nearest
+ * double character cell:
+ *
+ * [H BLANK (PIXELS)] = (ROUND(([TOTAL ACTIVE PIXELS] *
+ * [IDEAL DUTY CYCLE] /
+ * (100-[IDEAL DUTY CYCLE]) /
+ * (2*[CELL GRAN RND])), 0))
+ * * (2*[CELL GRAN RND])
+ */
+
+ h_blank = rint(total_active_pixels *
+ ideal_duty_cycle /
+ (100.0 - ideal_duty_cycle) /
+ (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN);
+
+ /* 20. Find total number of pixels:
+ *
+ * [TOTAL PIXELS] = [TOTAL ACTIVE PIXELS] + [H BLANK (PIXELS)]
+ */
+
+ total_pixels = total_active_pixels + h_blank;
+
+ /* 21. Find pixel clock frequency:
+ *
+ * [PIXEL FREQ] = [TOTAL PIXELS] / [H PERIOD]
+ */
+
+ pixel_freq = total_pixels / h_period;
+
+ /* 22. Find horizontal frequency:
+ *
+ * [H FREQ] = 1000 / [H PERIOD]
+ */
+
+ h_freq = 1000.0 / h_period;
+
+
+ /* Stage 1 computations are now complete; I should really pass
+ the results to another function and do the Stage 2
+ computations, but I only need a few more values so I'll just
+ append the computations here for now */
+
+
+
+ /* 17. Find the number of pixels in the horizontal sync period:
+ *
+ * [H SYNC (PIXELS)] =(ROUND(([H SYNC%] / 100 * [TOTAL PIXELS] /
+ * [CELL GRAN RND]),0))*[CELL GRAN RND]
+ */
+
+ h_sync = rint(H_SYNC_PERCENT/100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
+
+ /* 18. Find the number of pixels in the horizontal front porch period:
+ *
+ * [H FRONT PORCH (PIXELS)] = ([H BLANK (PIXELS)]/2)-[H SYNC (PIXELS)]
+ */
+
+ h_front_porch = (h_blank / 2.0) - h_sync;
+
+ /* 36. Find the number of lines in the odd front porch period:
+ *
+ * [V ODD FRONT PORCH(LINES)]=([MIN PORCH RND]+[INTERLACE])
+ */
+
+ v_odd_front_porch_lines = MIN_PORCH + interlace;
+
+ /* finally, pack the results in the DisplayMode struct */
+
+ m->HDisplay = (int) (h_pixels_rnd);
+ m->HSyncStart = (int) (h_pixels_rnd + h_front_porch);
+ m->HSyncEnd = (int) (h_pixels_rnd + h_front_porch + h_sync);
+ m->HTotal = (int) (total_pixels);
+
+ m->VDisplay = (int) (v_lines_rnd);
+ m->VSyncStart = (int) (v_lines_rnd + v_odd_front_porch_lines);
+ m->VSyncEnd = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD);
+ m->VTotal = (int) (total_v_lines);
+
+ m->Clock = (int)(pixel_freq * 1000);
+ m->SynthClock = m->Clock;
+ m->HSync = h_freq;
+ m->VRefresh = freq;
+
+ return (m);
+}
+
+static DisplayModePtr
+CheckMode(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe, int id,
+ int flags)
+{
+ CARD16 major, minor;
+ VbeModeInfoBlock *mode;
+ DisplayModePtr pMode = NULL;
+ VbeModeInfoData *data;
+ Bool modeOK = FALSE;
+ ModeStatus status = MODE_OK;
+
+ major = (unsigned)(vbe->VESAVersion >> 8);
+ minor = vbe->VESAVersion & 0xff;
+
+ if ((mode = VBEGetModeInfo(pVbe, id)) == NULL)
+ return NULL;
+
+ /* Does the mode match the depth/bpp? */
+ /* Some BIOS's set BitsPerPixel to 15 instead of 16 for 15/16 */
+ if (VBE_MODE_USABLE(mode, flags) &&
+ ((pScrn->bitsPerPixel == 1 && !VBE_MODE_COLOR(mode)) ||
+ (mode->BitsPerPixel > 8 &&
+ (mode->RedMaskSize + mode->GreenMaskSize +
+ mode->BlueMaskSize) == pScrn->depth &&
+ mode->BitsPerPixel == pScrn->bitsPerPixel) ||
+ (mode->BitsPerPixel == 15 && pScrn->depth == 15) ||
+ (mode->BitsPerPixel <= 8 &&
+ mode->BitsPerPixel == pScrn->bitsPerPixel))) {
+ modeOK = TRUE;
+ xf86ErrorFVerb(DEBUG_VERB, "*");
+ }
+
+ /*
+ * Check if there's a valid monitor mode that this one can be matched
+ * up with. The actual matching is done later.
+ */
+ if (modeOK) {
+ float vrefresh = 0.0f;
+ int i;
+
+ for (i=0;i<pScrn->monitor->nVrefresh;i++) {
+
+ for (vrefresh = pScrn->monitor->vrefresh[i].hi;
+ vrefresh >= pScrn->monitor->vrefresh[i].lo; vrefresh -= 1.0f) {
+
+ if (vrefresh != (float)0.0f) {
+ pMode = i830GetGTF(mode->XResolution, mode->YResolution,
+ vrefresh, 0, 0);
+
+ pMode->type = M_T_BUILTIN;
+
+ status = xf86CheckModeForMonitor(pMode, pScrn->monitor);
+ if (status == MODE_OK)
+ modeOK = TRUE;
+ else
+ modeOK = FALSE;
+ pMode->status = status;
+ } else {
+ modeOK = FALSE;
+ }
+ if (modeOK) break;
+ }
+ if (modeOK) break;
+ }
+ }
+
+ xf86ErrorFVerb(DEBUG_VERB,
+ "Mode: %x (%dx%d)\n", id, mode->XResolution, mode->YResolution);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " ModeAttributes: 0x%x\n", mode->ModeAttributes);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " WinAAttributes: 0x%x\n", mode->WinAAttributes);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " WinBAttributes: 0x%x\n", mode->WinBAttributes);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " WinGranularity: %d\n", mode->WinGranularity);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " WinSize: %d\n", mode->WinSize);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " WinASegment: 0x%x\n", mode->WinASegment);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " WinBSegment: 0x%x\n", mode->WinBSegment);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " WinFuncPtr: 0x%x\n", mode->WinFuncPtr);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " BytesPerScanline: %d\n", mode->BytesPerScanline);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " XResolution: %d\n", mode->XResolution);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " YResolution: %d\n", mode->YResolution);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " XCharSize: %d\n", mode->XCharSize);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " YCharSize: %d\n", mode->YCharSize);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " NumberOfPlanes: %d\n", mode->NumberOfPlanes);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " BitsPerPixel: %d\n", mode->BitsPerPixel);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " NumberOfBanks: %d\n", mode->NumberOfBanks);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " MemoryModel: %d\n", mode->MemoryModel);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " BankSize: %d\n", mode->BankSize);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " NumberOfImages: %d\n", mode->NumberOfImages);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " RedMaskSize: %d\n", mode->RedMaskSize);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " RedFieldPosition: %d\n", mode->RedFieldPosition);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " GreenMaskSize: %d\n", mode->GreenMaskSize);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " GreenFieldPosition: %d\n", mode->GreenFieldPosition);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " BlueMaskSize: %d\n", mode->BlueMaskSize);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " BlueFieldPosition: %d\n", mode->BlueFieldPosition);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " RsvdMaskSize: %d\n", mode->RsvdMaskSize);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " RsvdFieldPosition: %d\n", mode->RsvdFieldPosition);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " DirectColorModeInfo: %d\n", mode->DirectColorModeInfo);
+ if (major >= 2) {
+ xf86ErrorFVerb(DEBUG_VERB,
+ " PhysBasePtr: 0x%x\n", mode->PhysBasePtr);
+ if (major >= 3) {
+ xf86ErrorFVerb(DEBUG_VERB,
+ " LinBytesPerScanLine: %d\n", mode->LinBytesPerScanLine);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " BnkNumberOfImagePages: %d\n", mode->BnkNumberOfImagePages);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " LinNumberOfImagePages: %d\n", mode->LinNumberOfImagePages);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " LinRedMaskSize: %d\n", mode->LinRedMaskSize);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " LinRedFieldPosition: %d\n", mode->LinRedFieldPosition);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " LinGreenMaskSize: %d\n", mode->LinGreenMaskSize);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " LinGreenFieldPosition: %d\n", mode->LinGreenFieldPosition);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " LinBlueMaskSize: %d\n", mode->LinBlueMaskSize);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " LinBlueFieldPosition: %d\n", mode->LinBlueFieldPosition);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " LinRsvdMaskSize: %d\n", mode->LinRsvdMaskSize);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " LinRsvdFieldPosition: %d\n", mode->LinRsvdFieldPosition);
+ xf86ErrorFVerb(DEBUG_VERB,
+ " MaxPixelClock: %d\n", mode->MaxPixelClock);
+ }
+ }
+
+ if (!modeOK) {
+ VBEFreeModeInfo(mode);
+ if (pMode)
+ xfree(pMode);
+ return NULL;
+ }
+
+ pMode->status = MODE_OK;
+ pMode->type = M_T_BUILTIN;
+
+ /* for adjust frame */
+ pMode->HDisplay = mode->XResolution;
+ pMode->VDisplay = mode->YResolution;
+
+ data = xnfcalloc(sizeof(VbeModeInfoData), 1);
+ data->mode = id;
+ data->data = mode;
+ pMode->PrivSize = sizeof(VbeModeInfoData);
+ pMode->Private = (INT32*)data;
+ pMode->next = NULL;
+ return pMode;
+}
+
+/*
+ * Check the available BIOS modes, and extract those that match the
+ * requirements into the modePool. Note: modePool is a NULL-terminated
+ * list.
+ */
+
+DisplayModePtr
+i830GetModePool(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe,
+ int modeTypes)
+{
+ DisplayModePtr pMode, p = NULL, modePool = NULL;
+ int i = 0;
+
+ if (modeTypes & V_MODETYPE_VBE) {
+ while (vbe->VideoModePtr[i] != 0xffff) {
+ int id = vbe->VideoModePtr[i++];
+
+ if ((pMode = CheckMode(pScrn, pVbe, vbe, id, modeTypes)) != NULL) {
+ ModeStatus status = MODE_OK;
+
+ /* Check the mode against a specified virtual size (if any) */
+ if (pScrn->display->virtualX > 0 &&
+ pMode->HDisplay > pScrn->display->virtualX) {
+ status = MODE_VIRTUAL_X;
+ }
+ if (pScrn->display->virtualY > 0 &&
+ pMode->VDisplay > pScrn->display->virtualY) {
+ status = MODE_VIRTUAL_Y;
+ }
+ if (status != MODE_OK) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Not using mode \"%dx%d\" (%s)\n",
+ pMode->HDisplay, pMode->VDisplay,
+ xf86ModeStatusToString(status));
+ } else {
+ if (p == NULL) {
+ modePool = pMode;
+ } else {
+ p->next = pMode;
+ }
+ pMode->prev = NULL;
+ p = pMode;
+ }
+ }
+ }
+ }
+ if (modeTypes & V_MODETYPE_VGA) {
+ for (i = 0; i < 0x7F; i++) {
+ if ((pMode = CheckMode(pScrn, pVbe, vbe, i, modeTypes)) != NULL) {
+ ModeStatus status = MODE_OK;
+
+ /* Check the mode against a specified virtual size (if any) */
+ if (pScrn->display->virtualX > 0 &&
+ pMode->HDisplay > pScrn->display->virtualX) {
+ status = MODE_VIRTUAL_X;
+ }
+ if (pScrn->display->virtualY > 0 &&
+ pMode->VDisplay > pScrn->display->virtualY) {
+ status = MODE_VIRTUAL_Y;
+ }
+ if (status != MODE_OK) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Not using mode \"%dx%d\" (%s)\n",
+ pMode->HDisplay, pMode->VDisplay,
+ xf86ModeStatusToString(status));
+ } else {
+ if (p == NULL) {
+ modePool = pMode;
+ } else {
+ p->next = pMode;
+ }
+ pMode->prev = NULL;
+ p = pMode;
+ }
+ }
+ }
+ }
+ return modePool;
+}
+
+/*
+ * Go through the monitor modes and selecting the best set of
+ * parameters for each BIOS mode. Note: This is only supported in
+ * VBE version 3.0 or later.
+ */
+void
+i830SetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe)
+{
+ DisplayModePtr pMode;
+ VbeModeInfoData *data;
+
+ pMode = pScrn->modes;
+ do {
+ int clock;
+
+ data = (VbeModeInfoData*)pMode->Private;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Attempting to use %dHz refresh for mode \"%s\" (%x)\n",
+ (int)pMode->VRefresh, pMode->name, data->mode);
+ data->block = xcalloc(sizeof(VbeCRTCInfoBlock), 1);
+ data->block->HorizontalTotal = pMode->HTotal;
+ data->block->HorizontalSyncStart = pMode->HSyncStart;
+ data->block->HorizontalSyncEnd = pMode->HSyncEnd;
+ data->block->VerticalTotal = pMode->VTotal;
+ data->block->VerticalSyncStart = pMode->VSyncStart;
+ data->block->VerticalSyncEnd = pMode->VSyncEnd;
+ data->block->Flags = ((pMode->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) |
+ ((pMode->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0);
+ data->block->PixelClock = pMode->Clock * 1000;
+ /* XXX May not have this. */
+ clock = VBEGetPixelClock(pVbe, data->mode, data->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)
+ data->block->PixelClock = clock;
+ data->mode |= (1 << 11);
+ data->block->RefreshRate = ((double)(data->block->PixelClock) /
+ (double)(pMode->HTotal * pMode->VTotal)) * 100;
+
+ pMode = pMode->next;
+ } while (pMode != pScrn->modes);
+}
+
+void
+i830PrintModes(ScrnInfoPtr scrp)
+{
+ DisplayModePtr p;
+ float hsync, refresh = 0;
+ char *desc, *desc2, *prefix, *uprefix;
+
+ if (scrp == NULL)
+ return;
+
+ xf86DrvMsg(scrp->scrnIndex, scrp->virtualFrom, "Virtual size is %dx%d "
+ "(pitch %d)\n", scrp->virtualX, scrp->virtualY,
+ scrp->displayWidth);
+
+ p = scrp->modes;
+ if (p == NULL)
+ return;
+
+ do {
+ desc = desc2 = "";
+ if (p->HSync > 0.0)
+ hsync = p->HSync;
+ else if (p->HTotal > 0)
+ hsync = (float)p->Clock / (float)p->HTotal;
+ else
+ hsync = 0.0;
+ if (p->VTotal > 0)
+ refresh = hsync * 1000.0 / p->VTotal;
+ if (p->Flags & V_INTERLACE) {
+ refresh *= 2.0;
+ desc = " (I)";
+ }
+ if (p->Flags & V_DBLSCAN) {
+ refresh /= 2.0;
+ desc = " (D)";
+ }
+ if (p->VScan > 1) {
+ refresh /= p->VScan;
+ desc2 = " (VScan)";
+ }
+ if (p->VRefresh > 0.0)
+ refresh = p->VRefresh;
+ if (p->type & M_T_BUILTIN)
+ prefix = "Built-in mode";
+ else if (p->type & M_T_DEFAULT)
+ prefix = "Default mode";
+ else
+ prefix = "Mode";
+ if (p->type & M_T_USERDEF)
+ uprefix = "*";
+ else
+ uprefix = " ";
+ if (p->name)
+ xf86DrvMsg(scrp->scrnIndex, X_CONFIG,
+ "%s%s \"%s\"\n", uprefix, prefix, p->name);
+ else
+ xf86DrvMsg(scrp->scrnIndex, X_PROBED,
+ "%s%s %dx%d (unnamed)\n",
+ uprefix, prefix, p->HDisplay, p->VDisplay);
+ p = p->next;
+ } while (p != NULL && p != scrp->modes);
+}
diff --git a/src/i830_video.c b/src/i830_video.c
index 8cf7f451..6eb34da9 100644
--- a/src/i830_video.c
+++ b/src/i830_video.c
@@ -110,7 +110,7 @@ static void I830BlockHandler(int, pointer, pointer, pointer);
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
-static Atom xvBrightness, xvContrast, xvColorKey;
+static Atom xvBrightness, xvContrast, xvColorKey, xvPipe;
static Atom xvGamma0, xvGamma1, xvGamma2, xvGamma3, xvGamma4, xvGamma5;
#define IMAGE_MAX_WIDTH 1440
@@ -251,7 +251,7 @@ static XF86VideoFormatRec Formats[NUM_FORMATS] = {
{15, TrueColor}, {16, TrueColor}, {24, TrueColor}
};
-#define NUM_ATTRIBUTES 9
+#define NUM_ATTRIBUTES 10
static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = {
{XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
@@ -262,7 +262,8 @@ static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = {
{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA2"},
{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA3"},
{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA4"},
- {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA5"}
+ {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA5"},
+ {XvSettable | XvGettable, 0, 1, "XV_PIPE"}
};
#define NUM_IMAGES 4
@@ -342,6 +343,7 @@ typedef struct {
int brightness;
int contrast;
+ int pipe;
RegionRec clip;
CARD32 colorKey;
@@ -503,7 +505,7 @@ I830ResetVideo(ScrnInfoPtr pScrn)
* Select which pipe the overlay is enabled on.
*/
overlay->OCONFIG &= ~OVERLAY_PIPE_MASK;
- if (pI830->pipe == 0)
+ if (pPriv->pipe == 0)
overlay->OCONFIG |= OVERLAY_PIPE_A;
else
overlay->OCONFIG |= OVERLAY_PIPE_B;
@@ -589,7 +591,7 @@ I830SetupImageVideo(ScreenPtr pScreen)
adapt->type = XvWindowMask | XvInputMask | XvImageMask;
adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
- adapt->name = "Intel(R) 830M/845G/852GM/855GM/865G/915G Video Overlay";
+ adapt->name = "Intel(R) Video Overlay";
adapt->nEncodings = 1;
adapt->pEncodings = DummyEncoding;
adapt->nFormats = NUM_FORMATS;
@@ -602,10 +604,12 @@ I830SetupImageVideo(ScreenPtr pScreen)
adapt->pPortPrivates[0].ptr = (pointer) (pPriv);
adapt->pAttributes = Attributes;
adapt->nImages = NUM_IMAGES;
- if (IS_I915G(pI830))
+ if (IS_I915G(pI830) || IS_I915GM(pI830))
adapt->nAttributes = 9; /* has gamma */
else
adapt->nAttributes = 3;
+ if (pI830->Clone)
+ adapt->nAttributes += 1;
adapt->pImages = Images;
adapt->PutVideo = NULL;
adapt->PutStill = NULL;
@@ -622,6 +626,7 @@ I830SetupImageVideo(ScreenPtr pScreen)
pPriv->videoStatus = 0;
pPriv->brightness = 0;
pPriv->contrast = 64;
+ pPriv->pipe = pI830->pipe; /* default to current pipe */
pPriv->linear = NULL;
pPriv->currentBuf = 0;
pPriv->gamma5 = 0xc0c0c0;
@@ -655,7 +660,12 @@ I830SetupImageVideo(ScreenPtr pScreen)
xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
xvContrast = MAKE_ATOM("XV_CONTRAST");
xvColorKey = MAKE_ATOM("XV_COLORKEY");
- if (IS_I915G(pI830)) {
+
+ /* Allow the pipe to be switched from pipe A to B when in clone mode */
+ if (pI830->Clone)
+ xvPipe = MAKE_ATOM("XV_PIPE");
+
+ if (IS_I915G(pI830) || IS_I915GM(pI830)) {
xvGamma0 = MAKE_ATOM("XV_GAMMA0");
xvGamma1 = MAKE_ATOM("XV_GAMMA1");
xvGamma2 = MAKE_ATOM("XV_GAMMA2");
@@ -759,7 +769,21 @@ I830SetPortAttribute(ScrnInfoPtr pScrn,
overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff);
if (pPriv->overlayOK)
OVERLAY_UPDATE;
- } else if (attribute == xvGamma0 && (IS_I915G(pI830))) {
+ } else if (pI830->Clone && attribute == xvPipe) {
+ if ((value < 0) || (value > 1))
+ return BadValue;
+ pPriv->pipe = value;
+ /*
+ * Select which pipe the overlay is enabled on.
+ */
+ overlay->OCONFIG &= ~OVERLAY_PIPE_MASK;
+ if (pPriv->pipe == 0)
+ overlay->OCONFIG |= OVERLAY_PIPE_A;
+ else
+ overlay->OCONFIG |= OVERLAY_PIPE_B;
+ if (pPriv->overlayOK)
+ OVERLAY_UPDATE;
+ } else if (attribute == xvGamma0 && (IS_I915G(pI830) || IS_I915GM(pI830))) {
/* Avoid video anomalies, so set gamma registers when overlay is off */
/* We also clamp the values if they are outside the ranges */
if (!*pI830->overlayOn) {
@@ -768,35 +792,35 @@ I830SetPortAttribute(ScrnInfoPtr pScrn,
pPriv->gamma1 = pPriv->gamma0 + 0x7d;
} else
return BadRequest;
- } else if (attribute == xvGamma1 && (IS_I915G(pI830))) {
+ } else if (attribute == xvGamma1 && (IS_I915G(pI830) || IS_I915GM(pI830))) {
if (!*pI830->overlayOn) {
pPriv->gamma1 = value;
if (pPriv->gamma1 - pPriv->gamma0 > 0x7d)
pPriv->gamma0 = pPriv->gamma1 - 0x7d;
} else
return BadRequest;
- } else if (attribute == xvGamma2 && (IS_I915G(pI830))) {
+ } else if (attribute == xvGamma2 && (IS_I915G(pI830) || IS_I915GM(pI830))) {
if (!*pI830->overlayOn) {
pPriv->gamma2 = value;
if (pPriv->gamma3 - pPriv->gamma2 > 0x7d)
pPriv->gamma3 = pPriv->gamma2 + 0x7d;
} else
return BadRequest;
- } else if (attribute == xvGamma3 && (IS_I915G(pI830))) {
+ } else if (attribute == xvGamma3 && (IS_I915G(pI830) || IS_I915GM(pI830))) {
if (!*pI830->overlayOn) {
pPriv->gamma3 = value;
if (pPriv->gamma3 - pPriv->gamma2 > 0x7d)
pPriv->gamma2 = pPriv->gamma3 - 0x7d;
} else
return BadRequest;
- } else if (attribute == xvGamma4 && (IS_I915G(pI830))) {
+ } else if (attribute == xvGamma4 && (IS_I915G(pI830) || IS_I915GM(pI830))) {
if (!*pI830->overlayOn) {
pPriv->gamma4 = value;
if (pPriv->gamma5 - pPriv->gamma4 > 0x7d)
pPriv->gamma5 = pPriv->gamma4 + 0x7d;
} else
return BadRequest;
- } else if (attribute == xvGamma5 && (IS_I915G(pI830))) {
+ } else if (attribute == xvGamma5 && (IS_I915G(pI830) || IS_I915GM(pI830))) {
if (!*pI830->overlayOn) {
pPriv->gamma5 = value;
if (pPriv->gamma5 - pPriv->gamma4 > 0x7d)
@@ -828,7 +852,7 @@ I830SetPortAttribute(ScrnInfoPtr pScrn,
attribute == xvGamma2 ||
attribute == xvGamma3 ||
attribute == xvGamma4 ||
- attribute == xvGamma5) && (IS_I915G(pI830))) {
+ attribute == xvGamma5) && (IS_I915G(pI830) || IS_I915GM(pI830))) {
I830UpdateGamma(pScrn);
}
@@ -846,17 +870,19 @@ I830GetPortAttribute(ScrnInfoPtr pScrn,
*value = pPriv->brightness;
} else if (attribute == xvContrast) {
*value = pPriv->contrast;
- } else if (attribute == xvGamma0 && (IS_I915G(pI830))) {
+ } else if (pI830->Clone && attribute == xvPipe) {
+ *value = pPriv->pipe;
+ } else if (attribute == xvGamma0 && (IS_I915G(pI830) || IS_I915GM(pI830))) {
*value = pPriv->gamma0;
- } else if (attribute == xvGamma1 && (IS_I915G(pI830))) {
+ } else if (attribute == xvGamma1 && (IS_I915G(pI830) || IS_I915GM(pI830))) {
*value = pPriv->gamma1;
- } else if (attribute == xvGamma2 && (IS_I915G(pI830))) {
+ } else if (attribute == xvGamma2 && (IS_I915G(pI830) || IS_I915GM(pI830))) {
*value = pPriv->gamma2;
- } else if (attribute == xvGamma3 && (IS_I915G(pI830))) {
+ } else if (attribute == xvGamma3 && (IS_I915G(pI830) || IS_I915GM(pI830))) {
*value = pPriv->gamma3;
- } else if (attribute == xvGamma4 && (IS_I915G(pI830))) {
+ } else if (attribute == xvGamma4 && (IS_I915G(pI830) || IS_I915GM(pI830))) {
*value = pPriv->gamma4;
- } else if (attribute == xvGamma5 && (IS_I915G(pI830))) {
+ } else if (attribute == xvGamma5 && (IS_I915G(pI830) || IS_I915GM(pI830))) {
*value = pPriv->gamma5;
} else if (attribute == xvColorKey) {
*value = pPriv->colorKey;
@@ -1448,7 +1474,7 @@ I830PutImage(ScrnInfoPtr pScrn,
if (pI830->entityPrivate) {
if (pI830->entityPrivate->XvInUse != -1 &&
- pI830->entityPrivate->XvInUse != pI830->pipe) {
+ pI830->entityPrivate->XvInUse != pPriv->pipe) {
#ifdef PANORAMIX
if (!noPanoramiXExtension) {
return Success; /* faked for trying to share it */
@@ -1459,7 +1485,7 @@ I830PutImage(ScrnInfoPtr pScrn,
}
}
- pI830->entityPrivate->XvInUse = pI830->pipe;
+ pI830->entityPrivate->XvInUse = pPriv->pipe;
}
/* Clip */
@@ -1836,7 +1862,7 @@ I830DisplaySurface(XF86SurfacePtr surface,
if (pI830->entityPrivate) {
if (pI830->entityPrivate->XvInUse != -1 &&
- pI830->entityPrivate->XvInUse != pI830->pipe) {
+ pI830->entityPrivate->XvInUse != pI830Priv->pipe) {
#ifdef PANORAMIX
if (!noPanoramiXExtension) {
return Success; /* faked for trying to share it */
@@ -1847,7 +1873,7 @@ I830DisplaySurface(XF86SurfacePtr surface,
}
}
- pI830->entityPrivate->XvInUse = pI830->pipe;
+ pI830->entityPrivate->XvInUse = pI830Priv->pipe;
}
x1 = src_x;
@@ -1978,7 +2004,7 @@ I830VideoSwitchModeAfter(ScrnInfoPtr pScrn, DisplayModePtr mode)
if (!pPriv)
return;
- if (pI830->pipe == 0) {
+ if (pPriv->pipe == 0) {
if (INREG(PIPEACONF) & PIPEACONF_DOUBLE_WIDE) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Disabling XVideo output because Pipe A is in double-wide mode.\n");
@@ -1990,7 +2016,7 @@ I830VideoSwitchModeAfter(ScrnInfoPtr pScrn, DisplayModePtr mode)
}
}
- if (pI830->pipe == 1) {
+ if (pPriv->pipe == 1) {
if (INREG(PIPEBCONF) & PIPEBCONF_DOUBLE_WIDE) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Disabling XVideo output because Pipe B is in double-wide mode.\n");
@@ -2003,7 +2029,7 @@ I830VideoSwitchModeAfter(ScrnInfoPtr pScrn, DisplayModePtr mode)
}
/* Check we are on pipe B and have an LFP connected */
- if ((pI830->pipe == 1) && (pI830->operatingDevices & (PIPE_LFP << 8))) {
+ if ((pPriv->pipe == 1) && (pI830->operatingDevices & (PIPE_LFP << 8))) {
size = INREG(PIPEBSRC);
hsize = (size >> 16) & 0x7FF;
vsize = size & 0x7FF;