diff options
author | Eric Anholt <anholt@FreeBSD.org> | 2006-03-27 18:50:53 -0800 |
---|---|---|
committer | Eric Anholt <anholt@leguin.anholt.net> | 2006-04-06 15:59:51 -0700 |
commit | 33977d23830b5f9bb7d9e2e9c141f91cb127b7de (patch) | |
tree | 1ebdaa0b07352965c364d6d5b5ec49714e731874 | |
parent | febdfa967dbe1df487db71ba5f677ef37450bf7a (diff) |
Port code from radeon driver for panel mode validation, which will hopefully get
the right mode chosen on the VAIO. Untested.
-rw-r--r-- | src/i830.h | 3 | ||||
-rw-r--r-- | src/i830_bios.c | 10 | ||||
-rw-r--r-- | src/i830_driver.c | 313 |
3 files changed, 202 insertions, 124 deletions
@@ -430,6 +430,9 @@ typedef struct _I830Rec { struct _I830OutputRec output[MAX_OUTPUTS]; I830SDVOPtr sdvo; + /* Panel size pulled from the BIOS */ + int PanelXRes, PanelYRes; + /* The BIOS's fixed timings for the LVDS */ int panel_fixed_hactive; int panel_fixed_hblank; diff --git a/src/i830_bios.c b/src/i830_bios.c index 31e89b59..47c39ec3 100644 --- a/src/i830_bios.c +++ b/src/i830_bios.c @@ -102,6 +102,7 @@ i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScrn) struct bdb_header *bdb; int vbt_off, bdb_off, bdb_block_off, block_size; int panel_type = -1; + Bool found_panel_info = FALSE; if (!i830GetBIOS(pScrn)) return FALSE; @@ -147,9 +148,11 @@ i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScrn) timing_ptr = pI830->VBIOS + bdb_off + lvds2->panels[panel_type].fp_edid_dtd_offset; + pI830->PanelXRes = fpparam->x_res; + pI830->PanelYRes = fpparam->y_res; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found panel of size %dx%d in BIOS VBT tables\n", - fpparam->x_res, fpparam->y_res); + pI830->PanelXRes, pI830->PanelYRes); /* Since lvds_bdb_2_fp_edid_dtd is just an EDID detailed timing * block, pull the contents out using EDID macros. @@ -163,8 +166,11 @@ i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScrn) pI830->panel_fixed_vblank = _V_BLANK(timing_ptr); pI830->panel_fixed_vsyncoff = _V_SYNC_OFF(timing_ptr); pI830->panel_fixed_vsyncwidth = _V_SYNC_WIDTH(timing_ptr); + + found_panel_info = TRUE; break; } } - return TRUE; + + return found_panel_info; } diff --git a/src/i830_driver.c b/src/i830_driver.c index ca46ec99..c6b59708 100644 --- a/src/i830_driver.c +++ b/src/i830_driver.c @@ -183,6 +183,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include "i830.h" #include "i830_display.h" #include "i830_debug.h" +#include "i830_bios.h" #ifdef XF86DRI #include "dri.h" @@ -591,100 +592,6 @@ struct panelid { 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); -} - int I830GetBestRefresh(ScrnInfoPtr pScrn, int refresh) { @@ -2125,6 +2032,166 @@ I830IsPrimary(ScrnInfoPtr pScrn) return TRUE; } +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 = 0; /* XXX */ +} + +/** + * 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. + */ +static 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); + + return count; +} + static Bool I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) { @@ -3151,12 +3218,6 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) SetPipeAccess(pScrn); - /* 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) ) - vbeDoPanelID(pI830->pVbe); - /* XXX Move this to a header. */ #define VIDEO_BIOS_SCRATCH 0x18 @@ -3202,28 +3263,36 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags) clockRanges->interlaceAllowed = TRUE; /* XXX check this */ clockRanges->doubleScanAllowed = FALSE; /* XXX check this */ - /* - * XXX DDC information: There's code in xf86ValidateModes - * (VBEValidateModes) to set monitor defaults based on DDC information - * where available. If we need something that does better than this, - * there's code in vesa/vesa.c. - */ - - /* XXX minPitch, minHeight are random numbers. */ - n = xf86ValidateModes(pScrn, - pScrn->monitor->Modes, /* availModes */ - pScrn->display->modes, /* modeNames */ - clockRanges, /* clockRanges */ - NULL, /* linePitches */ - 256, /* minPitch */ - MAX_DISPLAY_PITCH, /* maxPitch */ - 64, /* pitchInc */ - pScrn->bitsPerPixel, /* minHeight */ - MAX_DISPLAY_HEIGHT, /* maxHeight */ - pScrn->display->virtualX, /* virtualX */ - pScrn->display->virtualY, /* virtualY */ - pI830->FbMapSize, /* apertureSize */ - LOOKUP_BEST_REFRESH /* strategy */); + if ( (pI830->pipe == 1 && pI830->operatingDevices & (PIPE_LFP << 8)) || + (pI830->pipe == 0 && pI830->operatingDevices & PIPE_LFP) ) { + /* If we're outputting to an LFP, use the LFP mode validation that will + * rely on the scaler so that we can display any mode smaller than or the + * same size as the panel. + */ + if (!i830GetLVDSInfoFromBIOS(pScrn)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unable to locate panel information in BIOS VBT tables\n"); + PreInitCleanup(pScrn); + return FALSE; + } + n = i830ValidateFPModes(pScrn, pScrn->display->modes); + } else { + /* XXX minPitch, minHeight are random numbers. */ + n = xf86ValidateModes(pScrn, + pScrn->monitor->Modes, /* availModes */ + pScrn->display->modes, /* modeNames */ + clockRanges, /* clockRanges */ + NULL, /* linePitches */ + 256, /* minPitch */ + MAX_DISPLAY_PITCH, /* maxPitch */ + 64, /* pitchInc */ + pScrn->bitsPerPixel, /* minHeight */ + MAX_DISPLAY_HEIGHT, /* maxHeight */ + pScrn->display->virtualX, /* virtualX */ + pScrn->display->virtualY, /* virtualY */ + pI830->FbMapSize, /* apertureSize */ + LOOKUP_BEST_REFRESH /* strategy */); + } if (n <= 0) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); PreInitCleanup(pScrn); |