summaryrefslogtreecommitdiff
path: root/src/i830_modes.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/i830_modes.c')
-rw-r--r--src/i830_modes.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/src/i830_modes.c b/src/i830_modes.c
index ce86d8ca..c0c258c2 100644
--- a/src/i830_modes.c
+++ b/src/i830_modes.c
@@ -332,6 +332,171 @@ DisplayModePtr I830xf86DDCModes(ScrnInfoPtr pScrn)
return first;
}
+static void
+i830SetModeToPanelParameters(ScrnInfoPtr pScrn, DisplayModePtr pMode)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+
+ pMode->HTotal = pI830->panel_fixed_hactive;
+ pMode->HSyncStart = pI830->panel_fixed_hactive + pI830->panel_fixed_hsyncoff;
+ pMode->HSyncEnd = pMode->HSyncStart + pI830->panel_fixed_hsyncwidth;
+ pMode->VTotal = pI830->panel_fixed_vactive;
+ pMode->VSyncStart = pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff;
+ pMode->VSyncEnd = pMode->VSyncStart + pI830->panel_fixed_vsyncwidth;
+ pMode->Clock = pI830->panel_fixed_clock;
+}
+
+/**
+ * This function returns a default mode for flat panels using the timing
+ * information provided by the BIOS.
+ */
+static DisplayModePtr i830FPNativeMode(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ DisplayModePtr new;
+ char stmp[32];
+
+ if (pI830->PanelXRes == 0 || pI830->PanelYRes == 0)
+ return NULL;
+
+ /* Add native panel size */
+ new = xnfcalloc(1, sizeof (DisplayModeRec));
+ sprintf(stmp, "%dx%d", pI830->PanelXRes, pI830->PanelYRes);
+ new->name = xnfalloc(strlen(stmp) + 1);
+ strcpy(new->name, stmp);
+ new->HDisplay = pI830->PanelXRes;
+ new->VDisplay = pI830->PanelYRes;
+ i830SetModeToPanelParameters(pScrn, new);
+ new->type = M_T_USERDEF;
+
+ pScrn->virtualX = MAX(pScrn->virtualX, pI830->PanelXRes);
+ pScrn->virtualY = MAX(pScrn->virtualY, pI830->PanelYRes);
+ pScrn->display->virtualX = pScrn->virtualX;
+ pScrn->display->virtualY = pScrn->virtualY;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "No valid mode specified, force to native mode\n");
+
+ return new;
+}
+
+/* FP mode validation routine for using panel fitting.
+ */
+int
+i830ValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ DisplayModePtr last = NULL;
+ DisplayModePtr new = NULL;
+ DisplayModePtr first = NULL;
+ DisplayModePtr p, tmp;
+ int count = 0;
+ int i, width, height;
+
+ pScrn->virtualX = pScrn->display->virtualX;
+ pScrn->virtualY = pScrn->display->virtualY;
+
+ /* We have a flat panel connected to the primary display, and we
+ * don't have any DDC info.
+ */
+ for (i = 0; ppModeName[i] != NULL; i++) {
+
+ if (sscanf(ppModeName[i], "%dx%d", &width, &height) != 2)
+ continue;
+
+ /* Note: We allow all non-standard modes as long as they do not
+ * exceed the native resolution of the panel. Since these modes
+ * need the internal RMX unit in the video chips (and there is
+ * only one per card), this will only apply to the primary head.
+ */
+ if (width < 320 || width > pI830->PanelXRes ||
+ height < 200 || height > pI830->PanelYRes) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Mode %s is out of range.\n",
+ ppModeName[i]);
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Valid modes must be between 320x200-%dx%d\n",
+ pI830->PanelXRes, pI830->PanelYRes);
+ continue;
+ }
+
+ new = xnfcalloc(1, sizeof(DisplayModeRec));
+ new->name = xnfalloc(strlen(ppModeName[i]) + 1);
+ strcpy(new->name, ppModeName[i]);
+ new->HDisplay = width;
+ new->VDisplay = height;
+ new->type |= M_T_USERDEF;
+
+ i830SetModeToPanelParameters(pScrn, new);
+
+ new->next = NULL;
+ new->prev = last;
+
+ if (last)
+ last->next = new;
+ last = new;
+ if (!first)
+ first = new;
+
+ pScrn->display->virtualX = pScrn->virtualX = MAX(pScrn->virtualX, width);
+ pScrn->display->virtualY = pScrn->virtualY = MAX(pScrn->virtualY, height);
+ count++;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Valid mode using panel fitting: %s\n", new->name);
+ }
+
+ /* If all else fails, add the native mode */
+ if (!count) {
+ first = last = i830FPNativeMode(pScrn);
+ if (first)
+ count = 1;
+ }
+
+ /* add in all default vesa modes smaller than panel size, used for randr*/
+ for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) {
+ if ((p->HDisplay <= pI830->PanelXRes) && (p->VDisplay <= pI830->PanelYRes)) {
+ tmp = first;
+ while (tmp) {
+ if ((p->HDisplay == tmp->HDisplay) && (p->VDisplay == tmp->VDisplay)) break;
+ tmp = tmp->next;
+ }
+ if (!tmp) {
+ new = xnfcalloc(1, sizeof(DisplayModeRec));
+ new->name = xnfalloc(strlen(p->name) + 1);
+ strcpy(new->name, p->name);
+ new->HDisplay = p->HDisplay;
+ new->VDisplay = p->VDisplay;
+ i830SetModeToPanelParameters(pScrn, new);
+ new->type |= M_T_DEFAULT;
+
+ new->next = NULL;
+ new->prev = last;
+
+ if (last)
+ last->next = new;
+ last = new;
+ if (!first)
+ first = new;
+ }
+ }
+ }
+
+ /* Close the doubly-linked mode list, if we found any usable modes */
+ if (last) {
+ last->next = first;
+ first->prev = last;
+ pScrn->modes = first;
+ }
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Total number of valid FP mode(s) found: %d\n", count);
+
+ /* Adjust the display pitch to fit the modes we've come up with. */
+ pScrn->displayWidth = MAX(pScrn->displayWidth, pScrn->virtualX);
+ pScrn->displayWidth = (pScrn->displayWidth + 63) & ~63;
+
+ return count;
+}
+
/* XFree86's xf86ValidateModes routine doesn't work well with DDC modes,
* so here is our own validation routine.
*/