diff options
Diffstat (limited to 'trunk/src/via_vbe.c')
-rw-r--r-- | trunk/src/via_vbe.c | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/trunk/src/via_vbe.c b/trunk/src/via_vbe.c new file mode 100644 index 000000000000..4122558bdeed --- /dev/null +++ b/trunk/src/via_vbe.c @@ -0,0 +1,451 @@ +/* + * Copyright 2004 The Unichrome Project [unichrome.sf.net] + * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com) + * + * 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, sub license, + * 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 (including the + * next paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. + */ +/* + * + * VBE Mode setting + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "via.h" +#include "via_driver.h" +#include "vbe.h" +#include "vbeModes.h" + +#define R16(v) ((v) & 0xffff) + +/* + * Functions more or less stolen from the vesa driver. Added to support BIOS modes directly. + */ + +void +ViaVbeAdjustFrame(int scrnIndex, int x, int y, int flags) +{ + VIAPtr pVia = VIAPTR(xf86Screens[scrnIndex]); + + VBESetDisplayStart(pVia->pVbe, x, y, TRUE); +} +/* + * Default values for pInt10 + */ +static void ViaVbeInitInt10(vbeInfoPtr pVbe) { + + pVbe->pInt10->ax = 0x4F14; + pVbe->pInt10->cx = 0; + pVbe->pInt10->dx = 0; + pVbe->pInt10->di = 0; + pVbe->pInt10->num = 0x10; +} + +static int ViaVbeGetRefreshRateIndex(int maxRefresh) { + + int rri ; + rri = 0 ; + + if (maxRefresh >= 120) { + rri = 10; + } else if (maxRefresh >= 100) { + rri = 9; + } else if (maxRefresh >= 85) { + rri = 7; + } else if (maxRefresh >= 75) { + rri = 5; + } else { + rri = 0; + } + + return rri ; +} + +/* + * + */ +static int ViaVbeGetActiveDevices(ScrnInfoPtr pScrn) { + + VIAPtr pVia = VIAPTR(pScrn); + VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo; + + int activeDevices; + activeDevices = 0 ; + + /* Set Active Device and Translate BIOS byte definition */ + if (pBIOSInfo->CrtActive) + activeDevices = 0x01; + if (pBIOSInfo->PanelActive) + activeDevices |= 0x02; + if (pBIOSInfo->TVActive) + activeDevices |= 0x04; + + /* TODO: Add others devices */ + + return activeDevices ; + +} + +/* + * Sets the requested mode, refresh rate and active devices + */ +static Bool ViaVbeSetActiveDevices( ScrnInfoPtr pScrn, int mode, int refresh ) { + + VIAPtr pVia = VIAPTR(pScrn); + VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo; + vbeInfoPtr pVbe = pVia->pVbe; + + ViaVbeInitInt10(pVbe); + pVbe->pInt10->bx = 0x8003; + pVbe->pInt10->cx = ViaVbeGetActiveDevices(pScrn); + pVbe->pInt10->dx = mode & 0x1FF; + pVbe->pInt10->di = ViaVbeGetRefreshRateIndex(refresh); + + DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "ViaVbeSetActiveDevices mode: %x, refresh: %d active devices: 0x%2x\n", + mode, refresh, pVbe->pInt10->cx )); + + xf86ExecX86int10(pVbe->pInt10); + if (pVbe->pInt10->ax != 0x4F) + return FALSE ; + + return TRUE; +} + +/* + * Sets the panel mode (expand or center) + */ +static Bool ViaVbeSetPanelMode(ScrnInfoPtr pScrn, Bool expand) { + + VIAPtr pVia = VIAPTR(pScrn); + VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo; + vbeInfoPtr pVbe = pVia->pVbe; + + DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaVbeSetPanelMode\n")); + + ViaVbeInitInt10(pVbe); + pVbe->pInt10->ax = 0x4F14; + pVbe->pInt10->bx = 0x0306; + pVbe->pInt10->cx = 0x80 | expand; + + xf86ExecX86int10(pVbe->pInt10); + + if (pVbe->pInt10->ax != 0x4F) + return FALSE; + + return TRUE; +} + +static Bool +ViaVbeSetRefresh(ScrnInfoPtr pScrn, int maxRefresh) +{ + VIAPtr pVia = VIAPTR(pScrn); + VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo; + + DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "ViaVbeSetRefresh\n")); + vbeInfoPtr pVbe = pVia->pVbe; + + ViaVbeInitInt10(pVbe); + pVbe->pInt10->bx = 0x0001; + pVbe->pInt10->cx = ViaVbeGetActiveDevices(pScrn); + + DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Active Device: %d\n", + pVbe->pInt10->cx)); + + pVbe->pInt10->di = ViaVbeGetRefreshRateIndex(maxRefresh); + + DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Refresh Rate Index: %d\n", + pVbe->pInt10->di)); + + /* Real execution */ + xf86ExecX86int10(pVbe->pInt10); + + if (pVbe->pInt10->ax != 0x4F) + return FALSE; + + return TRUE; +} + +Bool +ViaVbeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) +{ + VIAPtr pVia; + VbeModeInfoData *data; + pVia = VIAPTR(pScrn); + VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo; + int mode; + int refreshRate; + + pVia->OverlaySupported = FALSE; + + data = (VbeModeInfoData*)pMode->Private; + + mode = data->mode | (1 << 15); + + /* enable linear addressing */ + mode |= 1 << 14; + + if (data->block) { + refreshRate = data->block->RefreshRate; + } else { + refreshRate = VBE_DEFAULT_REFRESH; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Unable to determine the refresh rate, using %.2f. " + "Please check your configuration.\n", refreshRate/100.); + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Trying VBE Mode %dx%d (0x%x) Refresh %.2f:\n", + (int) data->data->XResolution, + (int) data->data->YResolution, + mode & ~(1 << 11), (float) refreshRate/100.); + + if (pVia->useLegacyVBE) { + + ViaVbeSetRefresh(pScrn, refreshRate/100); + + if (VBESetVBEMode(pVia->pVbe, mode, data->block) == FALSE) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBESetVBEMode failed"); + if ((data->block || (data->mode & (1 << 11))) && + VBESetVBEMode(pVia->pVbe, (mode & ~(1 << 11)), NULL) == TRUE) { + /* Some cards do not like setting the clock. + */ + xf86ErrorF("...but worked OK without customized refresh and dotclock.\n"); + xfree(data->block); + data->block = NULL; + data->mode &= ~(1 << 11); + } + else { + ErrorF("\n"); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed!\n"); + return (FALSE); + } + } + } else { + + if (pBIOSInfo->PanelActive && !pVia->useLegacyVBE) { + /* + * FIXME: should we always set the panel expansion? + * does it depend on the resolution? + */ + if (!ViaVbeSetPanelMode(pScrn, !pBIOSInfo->Center)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unable to set the panel mode.\n"); + } + } + + data->mode &= ~(1 << 11); + if (VBESetVBEMode(pVia->pVbe, data->mode, NULL) == FALSE) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Set VBE Mode failed.\n"); + return (FALSE); + } + + if (!ViaVbeSetActiveDevices(pScrn, data->mode, refreshRate/100)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to set the active devices.\n"); + return (FALSE); + } + } + + if (data->data->XResolution != pScrn->displayWidth) + VBESetLogicalScanline(pVia->pVbe, pScrn->displayWidth); + + pScrn->vtSema = TRUE; + + return (TRUE); +} + +Bool +ViaVbeSaveRestore(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function) +{ + VIAPtr pVia = VIAPTR(pScrn); + vgaHWPtr hwp = VGAHWPTR(pScrn); + + DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO,"ViaVbeSaveRestore\n")); + + if ((MODE_QUERY < 0) || (function > MODE_RESTORE)) + return (FALSE); + + if (function == MODE_SAVE) { + pVia->SavedReg.SR1A = hwp->readSeq(hwp, 0x1A); + } + + /* Query amount of memory to save state */ + if ((function == MODE_QUERY) || + ((function == MODE_SAVE) && (pVia->vbeMode.state == NULL))) { + + /* Make sure we save at least this information in case of failure */ + (void)VBEGetVBEMode(pVia->pVbe, &(pVia->vbeMode.stateMode)); + + if (pVia->vbeMode.major > 1) { + + if (!VBESaveRestore(pVia->pVbe, function, + (pointer) &(pVia->vbeMode.state), + &(pVia->vbeMode.stateSize), + &(pVia->vbeMode.statePage))) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING,"VBESaveRestore failed\n"); + return FALSE; + } + + } + } + + /* Save/Restore Super VGA state */ + if (function != MODE_QUERY) { + Bool retval = TRUE; + + if (pVia->vbeMode.major > 1) { + if (function == MODE_RESTORE) + memcpy(pVia->vbeMode.state, pVia->vbeMode.pstate, pVia->vbeMode.stateSize); + + if ((retval = VBESaveRestore(pVia->pVbe, function, + (pointer) &(pVia->vbeMode.state), + &(pVia->vbeMode.stateSize), + &(pVia->vbeMode.statePage))) + && (function == MODE_SAVE)) { + /* don't rely on the memory not being touched */ + if (pVia->vbeMode.pstate == NULL) + pVia->vbeMode.pstate = xalloc(pVia->vbeMode.stateSize); + memcpy(pVia->vbeMode.pstate, pVia->vbeMode.state, pVia->vbeMode.stateSize); + } + } + + if (function == MODE_RESTORE) { + if (!VBESetVBEMode(pVia->pVbe, pVia->vbeMode.stateMode, NULL)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING,"VBESetVBEMode failed\n"); + } + } + + if (!retval) + return (FALSE); + + } + + return (TRUE); +} + + +Bool +ViaVbeModePreInit(ScrnInfoPtr pScrn) +{ + VIAPtr pVia = VIAPTR(pScrn); + VbeInfoBlock *vbe; + VbeModeInfoBlock *vbeMode; + DisplayModePtr pMode; + int i; + + memset(&(pVia->vbeMode), 0, sizeof(ViaVbeModeInfo)); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Searching for matching VESA mode(s):\n"); + + if ((vbe = VBEGetVBEInfo(pVia->pVbe)) == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "VBEGetVBEInfo failed\n"); + return FALSE; + } + + pVia->vbeMode.major = (unsigned) (vbe->VESAVersion >> 8); + pVia->vbeMode.minor = vbe->VESAVersion & 0xff; + + pScrn->modePool = VBEGetModePool (pScrn, pVia->pVbe, vbe, V_MODETYPE_VBE); + if (pScrn->modePool == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No matching modes\n"); + return FALSE; + } + + VBESetModeNames(pScrn->modePool); + + i = VBEValidateModes(pScrn, NULL, pScrn->display->modes, + NULL, NULL, 0, 2048, 1, 0, 2048, + pScrn->display->virtualX, + pScrn->display->virtualY, + pScrn->videoRam, LOOKUP_BEST_REFRESH); + + + if (i <= 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); + return (FALSE); + } + + VBESetModeParameters(pScrn, pVia->pVbe); + + xf86PruneDriverModes(pScrn); +/* + pMode = pScrn->modes; + do { + vbeMode = ((VbeModeInfoData*)pMode->Private)->data; + pMode = pMode->next; + } while (pMode != NULL && pMode != pScrn->modes); +*/ + return TRUE; +} + +static int ViaVbePanelPower(vbeInfoPtr pVbe, int mode) +{ + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5F54; + pVbe->pInt10->bx = (mode) ? 0x00 : 0x01; + + xf86ExecX86int10(pVbe->pInt10); + + return (R16(pVbe->pInt10->ax) == 0x015f); +} + +#if 0 +/* + * FIXME: This might be useful in the future. Otherwise feel free to remove. + * if mode=1 sets the panel in a low power, low performance state. + * if mode=0 high performance. + */ + +static int ViaVbePanelLowPower(vbeInfoPtr pVbe, int mode) +{ + pVbe->pInt10->num = 0x10; + pVbe->pInt10->ax = 0x5F60; + pVbe->pInt10->bx = (mode) ? 0x01 : 0x00; + + xf86ExecX86int10(pVbe->pInt10); + + return (R16(pVbe->pInt10->ax) == 0x015f); +} +#endif + +void +ViaVbeDoDPMS(ScrnInfoPtr pScrn, int mode) +{ + VIAPtr pVia = VIAPTR(pScrn); + VIABIOSInfoPtr pBIOSInfo = pVia->pBIOSInfo; + + + if (pBIOSInfo->PanelActive) + ViaVbePanelPower(pVia->pVbe, (mode == DPMSModeOn)); + + VBEDPMSSet(pVia->pVbe,mode); +} + +void +ViaVbeDPMS(ScrnInfoPtr pScrn, int mode, int flags) +{ + if (!pScrn->vtSema) + return; + + ViaVbeDoDPMS(pScrn, mode); +} |