diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2007-09-30 14:18:15 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2007-09-30 14:18:15 +0000 |
commit | f25cb21322e90ab2c4d34d5bd8027006950662f6 (patch) | |
tree | f1986b6c009c7eba0d01e7a0297c5deec3163b97 /driver/xf86-video-nv/src | |
parent | da0ef05280ed34be0687c3802ab4724f7a9d063a (diff) |
xf86-video-nv 2.1.5
Diffstat (limited to 'driver/xf86-video-nv/src')
-rw-r--r-- | driver/xf86-video-nv/src/g80_cursor.c | 150 | ||||
-rw-r--r-- | driver/xf86-video-nv/src/g80_cursor.h | 8 | ||||
-rw-r--r-- | driver/xf86-video-nv/src/g80_dac.c | 208 | ||||
-rw-r--r-- | driver/xf86-video-nv/src/g80_exa.c | 329 | ||||
-rw-r--r-- | driver/xf86-video-nv/src/g80_exa.h | 1 | ||||
-rw-r--r-- | driver/xf86-video-nv/src/g80_output.c | 363 | ||||
-rw-r--r-- | driver/xf86-video-nv/src/g80_output.h | 31 | ||||
-rw-r--r-- | driver/xf86-video-nv/src/g80_sor.c | 500 | ||||
-rw-r--r-- | driver/xf86-video-nv/src/g80_xaa.h | 5 | ||||
-rw-r--r-- | driver/xf86-video-nv/src/local_xf86Rename.h | 23 | ||||
-rw-r--r-- | driver/xf86-video-nv/src/riva_const.h | 3 |
11 files changed, 1500 insertions, 121 deletions
diff --git a/driver/xf86-video-nv/src/g80_cursor.c b/driver/xf86-video-nv/src/g80_cursor.c index 07422e570..98a27362d 100644 --- a/driver/xf86-video-nv/src/g80_cursor.c +++ b/driver/xf86-video-nv/src/g80_cursor.c @@ -21,7 +21,6 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -36,36 +35,10 @@ #define CURSOR_PTR ((CARD32*)pNv->mem + pNv->videoRam * 256 - 0x1000) -static void G80SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) -{ - G80Ptr pNv = G80PTR(pScrn); - CARD32 *dst = CURSOR_PTR; - CARD32 *src = pNv->tmpCursor; - int i, j; - - fg |= 0xff000000; - bg |= 0xff000000; - - for(i = 0; i < 128; i++) { - CARD32 b = *src++; - CARD32 m = *src++; - - for(j = 0; j < 32; j++) { - if(m & 1) - *dst = (b & 1) ? fg : bg; - else - *dst = 0; - b >>= 1; - m >>= 1; - dst++; - } - } -} - -static void G80SetCursorPosition(ScrnInfoPtr pScrn, int x, int y) +void G80SetCursorPosition(xf86CrtcPtr crtc, int x, int y) { - G80Ptr pNv = G80PTR(pScrn); - const int headOff = 0x1000*pNv->head; + G80Ptr pNv = G80PTR(crtc->scrn); + const int headOff = 0x1000*G80CrtcGetHead(crtc); x &= 0xffff; y &= 0xffff; @@ -73,113 +46,58 @@ static void G80SetCursorPosition(ScrnInfoPtr pScrn, int x, int y) pNv->reg[(0x00647080 + headOff)/4] = 0; } -static void G80LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *bits) -{ - G80Ptr pNv = G80PTR(pScrn); - memcpy(pNv->tmpCursor, bits, sizeof(pNv->tmpCursor)); -} - -static void G80HideCursor(ScrnInfoPtr pScrn) +void G80LoadCursorARGB(xf86CrtcPtr crtc, CARD32 *src) { - G80Ptr pNv = G80PTR(pScrn); + G80Ptr pNv = G80PTR(crtc->scrn); + CARD32 *dst = CURSOR_PTR; - pNv->cursorVisible = FALSE; - G80DispHideCursor(G80PTR(pScrn), TRUE); + /* Assume cursor is 64x64 */ + memcpy(dst, src, 64 * 64 * 4); } -static void G80ShowCursor(ScrnInfoPtr pScrn) +Bool G80CursorAcquire(ScrnInfoPtr pScrn) { G80Ptr pNv = G80PTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; - pNv->cursorVisible = TRUE; - G80DispShowCursor(G80PTR(pScrn), TRUE); -} + if(!pNv->HWCursor) return TRUE; -static Bool G80UseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) -{ - return TRUE; -} + /* Initialize the cursor on each head */ + for(i = 0; i < xf86_config->num_crtc; i++) { + const int headOff = 0x10 * G80CrtcGetHead(xf86_config->crtc[i]); -#ifdef ARGB_CURSOR -static Bool G80UseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs) -{ - if((pCurs->bits->width <= 64) && (pCurs->bits->height <= 64)) - return TRUE; + pNv->reg[(0x00610270+headOff)/4] = 0x2000; + while(pNv->reg[(0x00610270+headOff)/4] & 0x30000); - return FALSE; -} - -static void G80LoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs) -{ - G80Ptr pNv = G80PTR(pScrn); - CARD32 *dst = CURSOR_PTR, *src = pCurs->bits->argb; - int y; - - for(y = 0; y < pCurs->bits->height; y++) { - memcpy(dst, src, pCurs->bits->width * 4); - memset(dst + pCurs->bits->width, 0, (64 - pCurs->bits->width) * 4); - src += pCurs->bits->width; - dst += 64; + pNv->reg[(0x00610270+headOff)/4] = 1; + while((pNv->reg[(0x00610270+headOff)/4] & 0x30000) != 0x10000); } - memset(dst, 0, (64 - y) * 64 * 4); -} -#endif - -Bool G80CursorAcquire(G80Ptr pNv) -{ - const int headOff = 0x10 * pNv->head; - - if(!pNv->HWCursor) return TRUE; - - pNv->reg[(0x00610270+headOff)/4] = 0x2000; - while(pNv->reg[(0x00610270+headOff)/4] & 0x30000); - - pNv->reg[(0x00610270+headOff)/4] = 1; - while((pNv->reg[(0x00610270+headOff)/4] & 0x30000) != 0x10000); - return TRUE; } -void G80CursorRelease(G80Ptr pNv) +void G80CursorRelease(ScrnInfoPtr pScrn) { - const int headOff = 0x10 * pNv->head; + G80Ptr pNv = G80PTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; if(!pNv->HWCursor) return; - pNv->reg[(0x00610270+headOff)/4] = 0; - while(pNv->reg[(0x00610270+headOff)/4] & 0x30000); + /* Release the cursor on each head */ + for(i = 0; i < xf86_config->num_crtc; i++) { + const int headOff = 0x10 * G80CrtcGetHead(xf86_config->crtc[i]); + + pNv->reg[(0x00610270+headOff)/4] = 0; + while(pNv->reg[(0x00610270+headOff)/4] & 0x30000); + } } Bool G80CursorInit(ScreenPtr pScreen) { - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - G80Ptr pNv = G80PTR(pScrn); - xf86CursorInfoPtr infoPtr; - - if(!pNv->HWCursor) - return TRUE; - - infoPtr = xf86CreateCursorInfoRec(); - if(!infoPtr) return FALSE; - - pNv->CursorInfo = infoPtr; - pNv->cursorVisible = FALSE; - - infoPtr->MaxWidth = infoPtr->MaxHeight = 64; - infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | - HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32; - infoPtr->SetCursorColors = G80SetCursorColors; - infoPtr->SetCursorPosition = G80SetCursorPosition; - infoPtr->LoadCursorImage = G80LoadCursorImage; - infoPtr->HideCursor = G80HideCursor; - infoPtr->ShowCursor = G80ShowCursor; - infoPtr->UseHWCursor = G80UseHWCursor; - -#ifdef ARGB_CURSOR - infoPtr->UseHWCursorARGB = G80UseHWCursorARGB; - infoPtr->LoadCursorARGB = G80LoadCursorARGB; -#endif - - return xf86InitCursor(pScreen, infoPtr); + return xf86_cursors_init(pScreen, 64, 64, + HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 | + HARDWARE_CURSOR_ARGB); } diff --git a/driver/xf86-video-nv/src/g80_cursor.h b/driver/xf86-video-nv/src/g80_cursor.h index 9cd56eead..4d81d803b 100644 --- a/driver/xf86-video-nv/src/g80_cursor.h +++ b/driver/xf86-video-nv/src/g80_cursor.h @@ -1,3 +1,7 @@ Bool G80CursorInit(ScreenPtr); -Bool G80CursorAcquire(G80Ptr); -void G80CursorRelease(G80Ptr); +Bool G80CursorAcquire(ScrnInfoPtr); +void G80CursorRelease(ScrnInfoPtr); + +/* CRTC cursor functions */ +void G80SetCursorPosition(xf86CrtcPtr crtc, int x, int y); +void G80LoadCursorARGB(xf86CrtcPtr crtc, CARD32 *src); diff --git a/driver/xf86-video-nv/src/g80_dac.c b/driver/xf86-video-nv/src/g80_dac.c new file mode 100644 index 000000000..30413cd50 --- /dev/null +++ b/driver/xf86-video-nv/src/g80_dac.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2007 NVIDIA, Corporation + * + * 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 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unistd.h> + +#define DPMS_SERVER +#include <X11/extensions/dpms.h> + +#include "g80_type.h" +#include "g80_display.h" +#include "g80_output.h" + +static void +G80DacSetPClk(xf86OutputPtr output, int pclk) +{ + G80Ptr pNv = G80PTR(output->scrn); + G80OutputPrivPtr pPriv = output->driver_private; + const int orOff = 0x800 * pPriv->or; + + pNv->reg[(0x00614280+orOff)/4] = 0; +} + +static void +G80DacDPMSSet(xf86OutputPtr output, int mode) +{ + G80Ptr pNv = G80PTR(output->scrn); + G80OutputPrivPtr pPriv = output->driver_private; + const int off = 0x800 * pPriv->or; + CARD32 tmp; + + /* + * DPMSModeOn everything on + * DPMSModeStandby hsync disabled, vsync enabled + * DPMSModeSuspend hsync enabled, vsync disabled + * DPMSModeOff sync disabled + */ + while(pNv->reg[(0x0061A004+off)/4] & 0x80000000); + + tmp = pNv->reg[(0x0061A004+off)/4]; + tmp &= ~0x7f; + tmp |= 0x80000000; + + if(mode == DPMSModeStandby || mode == DPMSModeOff) + tmp |= 1; + if(mode == DPMSModeSuspend || mode == DPMSModeOff) + tmp |= 4; + if(mode != DPMSModeOn) + tmp |= 0x10; + if(mode == DPMSModeOff) + tmp |= 0x40; + + pNv->reg[(0x0061A004+off)/4] = tmp; +} + +Bool +G80DacModeFixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + return TRUE; +} + +static void +G80DacModeSet(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + G80OutputPrivPtr pPriv = output->driver_private; + const int dacOff = 0x80 * pPriv->or; + + if(!adjusted_mode) { + C(0x00000400 + dacOff, 0); + return; + } + + // This wouldn't be necessary, but the server is stupid and calls + // G80DacDPMSSet after the output is disconnected, even though the hardware + // turns it off automatically. + G80DacDPMSSet(output, DPMSModeOn); + + C(0x00000400 + dacOff, + (G80CrtcGetHead(output->crtc) == HEAD0 ? 1 : 2) | 0x40); + C(0x00000404 + dacOff, + (adjusted_mode->Flags & V_NHSYNC) ? 1 : 0 | + (adjusted_mode->Flags & V_NVSYNC) ? 2 : 0); + + G80CrtcSetScale(output->crtc, adjusted_mode, G80_SCALE_OFF); +} + +/* + * Perform DAC load detection to determine if there is a connected display. + */ +static xf86OutputStatus +G80DacDetect(xf86OutputPtr output) +{ + G80OutputPrivPtr pPriv = output->driver_private; + + /* Assume physical status isn't going to change before the BlockHandler */ + if(pPriv->cached_status != XF86OutputStatusUnknown) + return pPriv->cached_status; + + G80OutputPartnersDetect(output, pPriv->partner, pPriv->i2c); + return pPriv->cached_status; +} + +Bool +G80DacLoadDetect(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + G80Ptr pNv = G80PTR(pScrn); + G80OutputPrivPtr pPriv = output->driver_private; + const int scrnIndex = pScrn->scrnIndex; + const int dacOff = 2048 * pPriv->or; + CARD32 load, tmp, tmp2; + + xf86DrvMsg(scrnIndex, X_PROBED, "Trying load detection on VGA%i ... ", + pPriv->or); + + pNv->reg[(0x0061A010+dacOff)/4] = 0x00000001; + tmp2 = pNv->reg[(0x0061A004+dacOff)/4]; + pNv->reg[(0x0061A004+dacOff)/4] = 0x80150000; + while(pNv->reg[(0x0061A004+dacOff)/4] & 0x80000000); + tmp = pNv->architecture == 0x50 ? 420 : 340; + pNv->reg[(0x0061A00C+dacOff)/4] = tmp | 0x100000; + usleep(4500); + load = pNv->reg[(0x0061A00C+dacOff)/4]; + pNv->reg[(0x0061A00C+dacOff)/4] = 0; + pNv->reg[(0x0061A004+dacOff)/4] = 0x80000000 | tmp2; + + // Use this DAC if all three channels show load. + if((load & 0x38000000) == 0x38000000) { + xf86ErrorF("found one!\n"); + return TRUE; + } + + xf86ErrorF("nothing.\n"); + return FALSE; +} + +static void +G80DacDestroy(xf86OutputPtr output) +{ + G80OutputDestroy(output); + + xfree(output->driver_private); + output->driver_private = NULL; +} + +static const xf86OutputFuncsRec G80DacOutputFuncs = { + .dpms = G80DacDPMSSet, + .save = NULL, + .restore = NULL, + .mode_valid = G80OutputModeValid, + .mode_fixup = G80DacModeFixup, + .prepare = G80OutputPrepare, + .commit = G80OutputCommit, + .mode_set = G80DacModeSet, + .detect = G80DacDetect, + .get_modes = G80OutputGetDDCModes, + .destroy = G80DacDestroy, +}; + +xf86OutputPtr +G80CreateDac(ScrnInfoPtr pScrn, ORNum or) +{ + G80OutputPrivPtr pPriv = xnfcalloc(sizeof(*pPriv), 1); + xf86OutputPtr output; + char orName[5]; + + if(!pPriv) + return FALSE; + + snprintf(orName, 5, "VGA%i", or); + output = xf86OutputCreate(pScrn, &G80DacOutputFuncs, orName); + + pPriv->type = DAC; + pPriv->or = or; + pPriv->cached_status = XF86OutputStatusUnknown; + pPriv->set_pclk = G80DacSetPClk; + output->driver_private = pPriv; + output->interlaceAllowed = TRUE; + output->doubleScanAllowed = TRUE; + + return output; +} diff --git a/driver/xf86-video-nv/src/g80_exa.c b/driver/xf86-video-nv/src/g80_exa.c new file mode 100644 index 000000000..96dbc2178 --- /dev/null +++ b/driver/xf86-video-nv/src/g80_exa.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2007 NVIDIA, Corporation + * + * 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 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. + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "g80_type.h" +#include "g80_dma.h" +#include "g80_xaa.h" + +static void +waitMarker(ScreenPtr pScreen, int marker) +{ + G80Sync(xf86Screens[pScreen->myNum]); +} + +static Bool +setSrc(G80Ptr pNv, PixmapPtr pSrc) +{ + CARD32 depth; + + switch(pSrc->drawable.depth) { + case 8: depth = 0x000000f3; break; + case 15: depth = 0x000000f8; break; + case 16: depth = 0x000000e8; break; + case 24: depth = 0x000000e6; break; + case 32: depth = 0x000000cf; break; + default: return FALSE; + } + + G80DmaStart(pNv, 0x230, 2); + G80DmaNext (pNv, depth); + G80DmaNext (pNv, 0x00000001); + G80DmaStart(pNv, 0x244, 5); + G80DmaNext (pNv, exaGetPixmapPitch(pSrc)); + G80DmaNext (pNv, pSrc->drawable.width); + G80DmaNext (pNv, pSrc->drawable.height); + G80DmaNext (pNv, 0x00000000); + G80DmaNext (pNv, exaGetPixmapOffset(pSrc)); + + return TRUE; +} + +static Bool +setDst(G80Ptr pNv, PixmapPtr pDst) +{ + CARD32 depth, depth2; + + switch(pDst->drawable.depth) { + case 8: depth = 0x000000f3; depth2 = 3; break; + case 15: depth = 0x000000f8; depth2 = 1; break; + case 16: depth = 0x000000e8; depth2 = 0; break; + case 24: depth = 0x000000e6; depth2 = 2; break; + case 32: depth = 0x000000cf; depth2 = 2; break; + default: return FALSE; + } + + G80DmaStart(pNv, 0x200, 2); + G80DmaNext (pNv, depth); + G80DmaNext (pNv, 0x00000001); + G80DmaStart(pNv, 0x214, 5); + G80DmaNext (pNv, exaGetPixmapPitch(pDst)); + G80DmaNext (pNv, pDst->drawable.width); + G80DmaNext (pNv, pDst->drawable.height); + G80DmaNext (pNv, 0x00000000); + G80DmaNext (pNv, exaGetPixmapOffset(pDst)); + G80DmaStart(pNv, 0x2e8, 1); + G80DmaNext (pNv, depth2); + G80DmaStart(pNv, 0x584, 1); + G80DmaNext (pNv, depth); + G80SetClip(pNv, 0, 0, pDst->drawable.width, pDst->drawable.height); + + return TRUE; +} + +/* solid fills */ + +static Bool +prepareSolid(PixmapPtr pPixmap, + int alu, + Pixel planemask, + Pixel fg) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + G80Ptr pNv = G80PTR(pScrn); + + if(pPixmap->drawable.depth > 24) return FALSE; + if(!setDst(pNv, pPixmap)) return FALSE; + G80DmaStart(pNv, 0x2ac, 1); + G80DmaNext (pNv, 1); + G80SetRopSolid(pNv, alu, planemask); + G80DmaStart(pNv, 0x580, 1); + G80DmaNext (pNv, 4); + G80DmaStart(pNv, 0x588, 1); + G80DmaNext (pNv, fg); + + pNv->DMAKickoffCallback = G80DMAKickoffCallback; + return TRUE; +} + +static void +solid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + G80Ptr pNv = G80PTR(pScrn); + + G80DmaStart(pNv, 0x600, 4); + G80DmaNext (pNv, x1); + G80DmaNext (pNv, y1); + G80DmaNext (pNv, x2); + G80DmaNext (pNv, y2); + + if((x2 - x1) * (y2 - y1) >= 512) + G80DmaKickoff(pNv); +} + +static void +doneSolid(PixmapPtr pPixmap) +{ +} + +/* screen to screen copies */ + +static Bool +prepareCopy(PixmapPtr pSrcPixmap, + PixmapPtr pDstPixmap, + int dx, + int dy, + int alu, + Pixel planemask) +{ + ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; + G80Ptr pNv = G80PTR(pScrn); + + if(!setSrc(pNv, pSrcPixmap)) return FALSE; + if(!setDst(pNv, pDstPixmap)) return FALSE; + G80DmaStart(pNv, 0x2ac, 1); + if(alu == GXcopy && planemask == ~0) { + G80DmaNext (pNv, 3); + } else { + G80DmaNext (pNv, 1); + G80SetRopSolid(pNv, alu, planemask); + } + pNv->DMAKickoffCallback = G80DMAKickoffCallback; + return TRUE; +} + +static void +copy(PixmapPtr pDstPixmap, + int srcX, + int srcY, + int dstX, + int dstY, + int width, + int height) +{ + ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; + G80Ptr pNv = G80PTR(pScrn); + + G80DmaStart(pNv, 0x110, 1); + G80DmaNext (pNv, 0); + G80DmaStart(pNv, 0x8b0, 12); + G80DmaNext (pNv, dstX); + G80DmaNext (pNv, dstY); + G80DmaNext (pNv, width); + G80DmaNext (pNv, height); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, 1); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, 1); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, srcX); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, srcY); + + if(width * height >= 512) + G80DmaKickoff(pNv); +} + +static void +doneCopy(PixmapPtr pDstPixmap) +{ +} + +/* composite */ + +static Bool +checkComposite(int op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst) +{ + return FALSE; +} + +/* upload to screen */ + +static Bool +upload(PixmapPtr pDst, + int x, + int y, + int w, + int h, + char *src, + int src_pitch) +{ + ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; + G80Ptr pNv = G80PTR(pScrn); + const int Bpp = pDst->drawable.bitsPerPixel >> 3; + int line_dwords = (w * Bpp + 3) / 4; + const Bool kickoff = w * h >= 512; + CARD32 depth; + + if(!setDst(pNv, pDst)) return FALSE; + switch(pDst->drawable.depth) { + case 8: depth = 0x000000f3; break; + case 15: depth = 0x000000f8; break; + case 16: depth = 0x000000e8; break; + case 24: depth = 0x000000e6; break; + case 32: depth = 0x000000cf; break; + default: return FALSE; + } + + G80SetClip(pNv, x, y, w, h); + G80DmaStart(pNv, 0x2ac, 1); + G80DmaNext (pNv, 3); + G80DmaStart(pNv, 0x800, 2); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, depth); + G80DmaStart(pNv, 0x838, 10); + G80DmaNext (pNv, (line_dwords * 4) / Bpp); + G80DmaNext (pNv, h); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, 1); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, 1); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, x); + G80DmaNext (pNv, 0); + G80DmaNext (pNv, y); + + while(h-- > 0) { + int count = line_dwords; + char *p = src; + + while(count) { + int size = count > 1792 ? 1792 : count; + + G80DmaStart(pNv, 0x40000860, size); + memcpy(&pNv->dmaBase[pNv->dmaCurrent], p, size * 4); + + p += size * Bpp; + pNv->dmaCurrent += size; + + count -= size; + } + + src += src_pitch; + } + + if(kickoff) + G80DmaKickoff(pNv); + else + pNv->DMAKickoffCallback = G80DMAKickoffCallback; + + return TRUE; +} + +/******************************************************************************/ + +Bool G80ExaInit(ScreenPtr pScreen, ScrnInfoPtr pScrn) +{ + G80Ptr pNv = G80PTR(pScrn); + ExaDriverPtr exa; + const int pitch = pScrn->displayWidth * (pScrn->bitsPerPixel / 8); + + exa = pNv->exa = exaDriverAlloc(); + if(!exa) return FALSE; + + exa->exa_major = EXA_VERSION_MAJOR; + exa->exa_minor = EXA_VERSION_MINOR; + exa->memoryBase = pNv->mem; + exa->offScreenBase = 0; + exa->memorySize = pitch * pNv->offscreenHeight; + exa->pixmapOffsetAlign = 256; + exa->pixmapPitchAlign = 256; + exa->flags = EXA_OFFSCREEN_PIXMAPS; + exa->maxX = 8192; + exa->maxY = 8192; + + /**** Rendering ops ****/ + exa->PrepareSolid = prepareSolid; + exa->Solid = solid; + exa->DoneSolid = doneSolid; + exa->PrepareCopy = prepareCopy; + exa->Copy = copy; + exa->DoneCopy = doneCopy; + exa->CheckComposite = checkComposite; + //exa->PrepareComposite = prepareComposite; + //exa->Composite = composite; + //exa->DoneComposite = doneComposite; + exa->UploadToScreen = upload; + + exa->WaitMarker = waitMarker; + + return exaDriverInit(pScreen, exa); +} diff --git a/driver/xf86-video-nv/src/g80_exa.h b/driver/xf86-video-nv/src/g80_exa.h new file mode 100644 index 000000000..2f01af621 --- /dev/null +++ b/driver/xf86-video-nv/src/g80_exa.h @@ -0,0 +1 @@ +Bool G80ExaInit(ScreenPtr pScreen, ScrnInfoPtr pScrn); diff --git a/driver/xf86-video-nv/src/g80_output.c b/driver/xf86-video-nv/src/g80_output.c new file mode 100644 index 000000000..1ec6a89af --- /dev/null +++ b/driver/xf86-video-nv/src/g80_output.c @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2007 NVIDIA, Corporation + * + * 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 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. + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <strings.h> + +#include "g80_type.h" +#include "g80_display.h" +#include "g80_output.h" + +static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv) +{ + unsigned char *table2; + unsigned char headerSize, entries; + int i; + CARD16 a; + CARD32 b; + + /* Clear the i2c map to invalid */ + for(i = 0; i < 4; i++) + pNv->i2cMap[i].dac = pNv->i2cMap[i].sor = -1; + + if(*(CARD16*)pNv->table1 != 0xaa55) goto fail; + + a = *(CARD16*)(pNv->table1 + 0x36); + table2 = (unsigned char*)pNv->table1 + a; + + if(table2[0] != 0x40) goto fail; + + b = *(CARD32*)(table2 + 6); + if(b != 0x4edcbdcb) goto fail; + + headerSize = table2[1]; + entries = table2[2]; + + for(i = 0; i < entries; i++) { + int type, port; + ORNum or; + + b = *(CARD32*)&table2[headerSize + 8*i]; + type = b & 0xf; + port = (b >> 4) & 0xf; + or = ffs((b >> 24) & 0xf) - 1; + + if(type == 0xe) break; + + if(type < 4) { + switch(type) { + case 0: /* CRT */ + if(pNv->i2cMap[port].dac != -1) { + xf86DrvMsg(scrnIndex, X_WARNING, + "DDC routing table corrupt! DAC %i -> %i " + "for port %i\n", + or, pNv->i2cMap[port].dac, port); + } + pNv->i2cMap[port].dac = or; + break; + case 1: /* TV */ + /* Ignore TVs */ + break; + + case 2: /* TMDS */ + if(pNv->i2cMap[port].sor != -1) + xf86DrvMsg(scrnIndex, X_WARNING, + "DDC routing table corrupt! SOR %i -> %i " + "for port %i\n", + or, pNv->i2cMap[port].sor, port); + pNv->i2cMap[port].sor = or; + break; + + case 3: /* LVDS */ + pNv->lvds.present = TRUE; + pNv->lvds.or = or; + break; + } + } + } + + xf86DrvMsg(scrnIndex, X_PROBED, "Connector map:\n"); + if(pNv->lvds.present) + xf86DrvMsg(scrnIndex, X_PROBED, " [N/A] -> SOR%i (LVDS)\n", pNv->lvds.or); + for(i = 0; i < 4; i++) { + if(pNv->i2cMap[i].dac != -1) + xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> DAC%i\n", i, pNv->i2cMap[i].dac); + if(pNv->i2cMap[i].sor != -1) + xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> SOR%i\n", i, pNv->i2cMap[i].sor); + } + + return TRUE; + +fail: + xf86DrvMsg(scrnIndex, X_ERROR, "Couldn't find the DDC routing table. " + "Mode setting will probably fail!\n"); + return FALSE; +} + +static void G80_I2CPutBits(I2CBusPtr b, int clock, int data) +{ + G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]); + const int off = b->DriverPrivate.val * 0x18; + + pNv->reg[(0x0000E138+off)/4] = 4 | clock | data << 1; +} + +static void G80_I2CGetBits(I2CBusPtr b, int *clock, int *data) +{ + G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]); + const int off = b->DriverPrivate.val * 0x18; + unsigned char val; + + val = pNv->reg[(0x0000E138+off)/4]; + *clock = !!(val & 1); + *data = !!(val & 2); +} + +static I2CBusPtr +G80I2CInit(ScrnInfoPtr pScrn, const char *name, const int port) +{ + I2CBusPtr i2c; + + /* Allocate the I2C bus structure */ + i2c = xf86CreateI2CBusRec(); + if(!i2c) return NULL; + + i2c->BusName = strdup(name); + i2c->scrnIndex = pScrn->scrnIndex; + i2c->I2CPutBits = G80_I2CPutBits; + i2c->I2CGetBits = G80_I2CGetBits; + i2c->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ + i2c->StartTimeout = 550; + i2c->BitTimeout = 40; + i2c->ByteTimeout = 40; + i2c->AcknTimeout = 40; + i2c->DriverPrivate.val = port; + + if(xf86I2CBusInit(i2c)) { + return i2c; + } else { + xfree(i2c); + return NULL; + } +} + +void +G80OutputSetPClk(xf86OutputPtr output, int pclk) +{ + G80OutputPrivPtr pPriv = output->driver_private; + if(pPriv->set_pclk) + pPriv->set_pclk(output, pclk); +} + +int +G80OutputModeValid(xf86OutputPtr output, DisplayModePtr mode) +{ + if(mode->Clock > 400000) + return MODE_CLOCK_HIGH; + if(mode->Clock < 25000) + return MODE_CLOCK_LOW; + + return MODE_OK; +} + +void +G80OutputPrepare(xf86OutputPtr output) +{ +} + +void +G80OutputCommit(xf86OutputPtr output) +{ +} + +static xf86MonPtr +ProbeDDC(I2CBusPtr i2c) +{ + ScrnInfoPtr pScrn = xf86Screens[i2c->scrnIndex]; + G80Ptr pNv = G80PTR(pScrn); + xf86MonPtr monInfo = NULL; + const int bus = i2c->DriverPrivate.val, off = bus * 0x18; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Probing for EDID on I2C bus %i...\n", bus); + pNv->reg[(0x0000E138+off)/4] = 7; + /* Should probably use xf86OutputGetEDID here */ + monInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, i2c); + pNv->reg[(0x0000E138+off)/4] = 3; + + if(monInfo) { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "DDC detected a %s:\n", monInfo->features.input_type ? + "DFP" : "CRT"); + xf86PrintEDID(monInfo); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, " ... none found\n"); + } + + return monInfo; +} + +/* + * Read an EDID from the i2c port. Perform load detection on the DAC (if + * present) to see if the display is connected via VGA. Sets the cached status + * of both outputs. The status is marked dirty again in the BlockHandler. + */ +void G80OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c) +{ + xf86MonPtr monInfo = ProbeDDC(i2c); + xf86OutputPtr connected = NULL; + Bool load = dac && G80DacLoadDetect(dac); + + if(dac) { + G80OutputPrivPtr pPriv = dac->driver_private; + + if(load) { + pPriv->cached_status = XF86OutputStatusConnected; + connected = dac; + } else { + pPriv->cached_status = XF86OutputStatusDisconnected; + } + } + + if(sor) { + G80OutputPrivPtr pPriv = sor->driver_private; + + if(monInfo && !load) { + pPriv->cached_status = XF86OutputStatusConnected; + connected = sor; + } else { + pPriv->cached_status = XF86OutputStatusDisconnected; + } + } + + if(connected) + xf86OutputSetEDID(connected, monInfo); +} + +/* + * Reset the cached output status for all outputs. Called from G80BlockHandler. + */ +void +G80OutputResetCachedStatus(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; + + for(i = 0; i < xf86_config->num_output; i++) { + G80OutputPrivPtr pPriv = xf86_config->output[i]->driver_private; + pPriv->cached_status = XF86OutputStatusUnknown; + } +} + +DisplayModePtr +G80OutputGetDDCModes(xf86OutputPtr output) +{ + /* The EDID is read as part of the detect step */ + output->funcs->detect(output); + return xf86OutputGetEDIDModes(output); +} + +void +G80OutputDestroy(xf86OutputPtr output) +{ + G80OutputPrivPtr pPriv = output->driver_private; + + if(pPriv->partner) + ((G80OutputPrivPtr)pPriv->partner->driver_private)->partner = NULL; + else + xf86DestroyI2CBusRec(pPriv->i2c, TRUE, TRUE); + pPriv->i2c = NULL; +} + +Bool +G80CreateOutputs(ScrnInfoPtr pScrn) +{ + G80Ptr pNv = G80PTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; + + if(!G80ReadPortMapping(pScrn->scrnIndex, pNv)) + return FALSE; + + /* For each DDC port, create an output for the attached ORs */ + for(i = 0; i < 4; i++) { + xf86OutputPtr dac = NULL, sor = NULL; + I2CBusPtr i2c; + char i2cName[16]; + + if(pNv->i2cMap[i].dac == -1 && pNv->i2cMap[i].sor == -1) + /* No outputs on this port */ + continue; + + snprintf(i2cName, sizeof(i2cName), "I2C%i", i); + i2c = G80I2CInit(pScrn, i2cName, i); + if(!i2c) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to initialize I2C for port %i.\n", + i); + continue; + } + + if(pNv->i2cMap[i].dac != -1) + dac = G80CreateDac(pScrn, pNv->i2cMap[i].dac); + if(pNv->i2cMap[i].sor != -1) + sor = G80CreateSor(pScrn, pNv->i2cMap[i].sor, TMDS); + + if(dac) { + G80OutputPrivPtr pPriv = dac->driver_private; + + pPriv->partner = sor; + pPriv->i2c = i2c; + pPriv->scale = G80_SCALE_OFF; + } + if(sor) { + G80OutputPrivPtr pPriv = sor->driver_private; + + pPriv->partner = dac; + pPriv->i2c = i2c; + pPriv->scale = G80_SCALE_ASPECT; + } + } + + if(pNv->lvds.present) { + xf86OutputPtr lvds = G80CreateSor(pScrn, pNv->lvds.or, LVDS); + G80OutputPrivPtr pPriv = lvds->driver_private; + + pPriv->scale = G80_SCALE_ASPECT; + } + + /* For each output, set the crtc and clone masks */ + for(i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + + /* Any output can connect to any head */ + output->possible_crtcs = 0x3; + output->possible_clones = 0; + } + + return TRUE; +} diff --git a/driver/xf86-video-nv/src/g80_output.h b/driver/xf86-video-nv/src/g80_output.h new file mode 100644 index 000000000..33514c61f --- /dev/null +++ b/driver/xf86-video-nv/src/g80_output.h @@ -0,0 +1,31 @@ +typedef struct G80OutputPrivRec { + ORType type; + ORNum or; + PanelType panelType; + DisplayModePtr nativeMode; + enum G80ScaleMode scale; + + xf86OutputPtr partner; + I2CBusPtr i2c; + + xf86OutputStatus cached_status; + + void (*set_pclk)(xf86OutputPtr, int pclk); +} G80OutputPrivRec, *G80OutputPrivPtr; + +void G80OutputSetPClk(xf86OutputPtr, int pclk); +int G80OutputModeValid(xf86OutputPtr, DisplayModePtr); +void G80OutputPrepare(xf86OutputPtr); +void G80OutputCommit(xf86OutputPtr); +void G80OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c); +void G80OutputResetCachedStatus(ScrnInfoPtr); +DisplayModePtr G80OutputGetDDCModes(xf86OutputPtr); +void G80OutputDestroy(xf86OutputPtr); +Bool G80CreateOutputs(ScrnInfoPtr); + +/* g80_dac.c */ +xf86OutputPtr G80CreateDac(ScrnInfoPtr, ORNum); +Bool G80DacLoadDetect(xf86OutputPtr); + +/* g80_sor.c */ +xf86OutputPtr G80CreateSor(ScrnInfoPtr, ORNum, PanelType); diff --git a/driver/xf86-video-nv/src/g80_sor.c b/driver/xf86-video-nv/src/g80_sor.c new file mode 100644 index 000000000..c98b66d42 --- /dev/null +++ b/driver/xf86-video-nv/src/g80_sor.c @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2007 NVIDIA, Corporation + * + * 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 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define DPMS_SERVER +#include <X11/extensions/dpms.h> +#include <X11/Xatom.h> + +#include "g80_type.h" +#include "g80_display.h" +#include "g80_output.h" + +static void +G80SorSetPClk(xf86OutputPtr output, int pclk) +{ + G80Ptr pNv = G80PTR(output->scrn); + G80OutputPrivPtr pPriv = output->driver_private; + const int orOff = 0x800 * pPriv->or; + const int limit = 165000; + + pNv->reg[(0x00614300+orOff)/4] = (pclk > limit) ? 0x101 : 0; +} + +static void +G80SorDPMSSet(xf86OutputPtr output, int mode) +{ + G80Ptr pNv = G80PTR(output->scrn); + G80OutputPrivPtr pPriv = output->driver_private; + const int off = 0x800 * pPriv->or; + CARD32 tmp; + + while(pNv->reg[(0x0061C004+off)/4] & 0x80000000); + + tmp = pNv->reg[(0x0061C004+off)/4]; + tmp |= 0x80000000; + + if(mode == DPMSModeOn) + tmp |= 1; + else + tmp &= ~1; + + pNv->reg[(0x0061C004+off)/4] = tmp; + while((pNv->reg[(0x61C030+off)/4] & 0x10000000)); +} + +static int +G80TMDSModeValid(xf86OutputPtr output, DisplayModePtr mode) +{ + // Disable dual-link modes until I can find a way to make them work + // reliably. + if (mode->Clock > 165000) + return MODE_CLOCK_HIGH; + + return G80OutputModeValid(output, mode); +} + +static int +G80LVDSModeValid(xf86OutputPtr output, DisplayModePtr mode) +{ + G80OutputPrivPtr pPriv = output->driver_private; + DisplayModePtr native = pPriv->nativeMode; + + // Ignore modes larger than the native res. + if (mode->HDisplay > native->HDisplay || mode->VDisplay > native->VDisplay) + return MODE_PANEL; + + return G80OutputModeValid(output, mode); +} + +static void +G80SorModeSet(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + G80OutputPrivPtr pPriv = output->driver_private; + const int sorOff = 0x40 * pPriv->or; + CARD32 type; + + if(!adjusted_mode) { + /* Disconnect the SOR */ + C(0x00000600 + sorOff, 0); + return; + } + + if(pPriv->panelType == LVDS) + type = 0; + else if(adjusted_mode->Clock > 165000) + type = 0x500; + else + type = 0x100; + + // This wouldn't be necessary, but the server is stupid and calls + // G80SorDPMSSet after the output is disconnected, even though the hardware + // turns it off automatically. + G80SorDPMSSet(output, DPMSModeOn); + + C(0x00000600 + sorOff, + (G80CrtcGetHead(output->crtc) == HEAD0 ? 1 : 2) | + type | + ((adjusted_mode->Flags & V_NHSYNC) ? 0x1000 : 0) | + ((adjusted_mode->Flags & V_NVSYNC) ? 0x2000 : 0)); + + G80CrtcSetScale(output->crtc, adjusted_mode, pPriv->scale); +} + +static xf86OutputStatus +G80SorDetect(xf86OutputPtr output) +{ + G80OutputPrivPtr pPriv = output->driver_private; + + /* Assume physical status isn't going to change before the BlockHandler */ + if(pPriv->cached_status != XF86OutputStatusUnknown) + return pPriv->cached_status; + + G80OutputPartnersDetect(pPriv->partner, output, pPriv->i2c); + return pPriv->cached_status; +} + +static xf86OutputStatus +G80SorLVDSDetect(xf86OutputPtr output) +{ + /* Assume LVDS is always connected */ + return XF86OutputStatusConnected; +} + +static void +G80SorDestroy(xf86OutputPtr output) +{ + G80OutputPrivPtr pPriv = output->driver_private; + + G80OutputDestroy(output); + + xf86DeleteMode(&pPriv->nativeMode, pPriv->nativeMode); + + xfree(output->driver_private); + output->driver_private = NULL; +} + +static void G80SorSetModeBackend(DisplayModePtr dst, const DisplayModePtr src) +{ + // Stash the backend mode timings from src into dst + dst->Clock = src->Clock; + dst->Flags = src->Flags; + dst->CrtcHDisplay = src->CrtcHDisplay; + dst->CrtcHBlankStart = src->CrtcHBlankStart; + dst->CrtcHSyncStart = src->CrtcHSyncStart; + dst->CrtcHSyncEnd = src->CrtcHSyncEnd; + dst->CrtcHBlankEnd = src->CrtcHBlankEnd; + dst->CrtcHTotal = src->CrtcHTotal; + dst->CrtcHSkew = src->CrtcHSkew; + dst->CrtcVDisplay = src->CrtcVDisplay; + dst->CrtcVBlankStart = src->CrtcVBlankStart; + dst->CrtcVSyncStart = src->CrtcVSyncStart; + dst->CrtcVSyncEnd = src->CrtcVSyncEnd; + dst->CrtcVBlankEnd = src->CrtcVBlankEnd; + dst->CrtcVTotal = src->CrtcVTotal; + dst->CrtcHAdjusted = src->CrtcHAdjusted; + dst->CrtcVAdjusted = src->CrtcVAdjusted; +} + +static Bool +G80SorModeFixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + G80OutputPrivPtr pPriv = output->driver_private; + DisplayModePtr native = pPriv->nativeMode; + + if(native && pPriv->scale != G80_SCALE_OFF) { + G80SorSetModeBackend(adjusted_mode, native); + // This mode is already "fixed" + G80CrtcSkipModeFixup(output->crtc); + } + + return TRUE; +} + +static Bool +G80SorTMDSModeFixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + int scrnIndex = output->scrn->scrnIndex; + G80OutputPrivPtr pPriv = output->driver_private; + DisplayModePtr modes = output->probed_modes; + + xf86DeleteMode(&pPriv->nativeMode, pPriv->nativeMode); + + if(modes) { + // Find the preferred mode and use that as the "native" mode. + // If no preferred mode is available, use the first one. + DisplayModePtr mode; + + // Find the preferred mode. + for(mode = modes; mode; mode = mode->next) { + if(mode->type & M_T_PREFERRED) { + xf86DrvMsgVerb(scrnIndex, X_INFO, 5, + "%s: preferred mode is %s\n", + output->name, mode->name); + break; + } + } + + // XXX: May not want to allow scaling if no preferred mode is found. + if(!mode) { + mode = modes; + xf86DrvMsgVerb(scrnIndex, X_INFO, 5, + "%s: no preferred mode found, using %s\n", + output->name, mode->name); + } + + pPriv->nativeMode = xf86DuplicateMode(mode); + G80CrtcDoModeFixup(pPriv->nativeMode, mode); + } + + return G80SorModeFixup(output, mode, adjusted_mode); +} + +static DisplayModePtr +G80SorGetLVDSModes(xf86OutputPtr output) +{ + G80OutputPrivPtr pPriv = output->driver_private; + return xf86DuplicateMode(pPriv->nativeMode); +} + +#ifdef RANDR_12_INTERFACE +#define MAKE_ATOM(a) MakeAtom((a), sizeof(a) - 1, TRUE); + +struct property { + Atom atom; + INT32 range[2]; +}; + +static struct { + struct property dither; + struct property scale; +} properties; + +static void +G80SorCreateResources(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + G80Ptr pNv = G80PTR(pScrn); + int data, err; + const char *s; + + /******** dithering ********/ + properties.dither.atom = MAKE_ATOM("dither"); + properties.dither.range[0] = 0; + properties.dither.range[1] = 1; + err = RRConfigureOutputProperty(output->randr_output, + properties.dither.atom, FALSE, TRUE, FALSE, + 2, properties.dither.range); + if(err) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to configure dithering property for %s: error %d\n", + output->name, err); + + // Set the default value + data = pNv->Dither; + err = RRChangeOutputProperty(output->randr_output, properties.dither.atom, + XA_INTEGER, 32, PropModeReplace, 1, &data, + FALSE, FALSE); + if(err) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to set dithering property for %s: error %d\n", + output->name, err); + + /******** scaling ********/ + properties.scale.atom = MAKE_ATOM("scale"); + err = RRConfigureOutputProperty(output->randr_output, + properties.scale.atom, FALSE, FALSE, + FALSE, 0, NULL); + if(err) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to configure scaling property for %s: error %d\n", + output->name, err); + + // Set the default value + s = "aspect"; + err = RRChangeOutputProperty(output->randr_output, properties.scale.atom, + XA_STRING, 8, PropModeReplace, strlen(s), + (pointer)s, FALSE, FALSE); + if(err) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to set scaling property for %s: error %d\n", + output->name, err); +} + +static Bool +G80SorSetProperty(xf86OutputPtr output, Atom prop, RRPropertyValuePtr val) +{ + G80OutputPrivPtr pPriv = output->driver_private; + + if(prop == properties.dither.atom) { + INT32 i; + + if(val->type != XA_INTEGER || val->format != 32 || val->size != 1) + return FALSE; + + i = *(INT32*)val->data; + if(i < properties.dither.range[0] || i > properties.dither.range[1]) + return FALSE; + + G80CrtcSetDither(output->crtc, i, TRUE); + return TRUE; + } else if(prop == properties.scale.atom) { + const char *s; + enum G80ScaleMode oldScale, scale; + int i; + const struct { + const char *name; + enum G80ScaleMode scale; + } modes[] = { + { "off", G80_SCALE_OFF }, + { "aspect", G80_SCALE_ASPECT }, + { "fill", G80_SCALE_FILL }, + { "center", G80_SCALE_CENTER }, + { NULL, 0 }, + }; + + if(val->type != XA_STRING || val->format != 8) + return FALSE; + s = (char*)val->data; + + for(i = 0; modes[i].name; i++) { + const char *name = modes[i].name; + const int len = strlen(name); + + if(val->size == len && !strncmp(name, s, len)) { + scale = modes[i].scale; + break; + } + } + if(!modes[i].name) + return FALSE; + if(scale == G80_SCALE_OFF && pPriv->panelType == LVDS) + // LVDS requires scaling + return FALSE; + + oldScale = pPriv->scale; + pPriv->scale = scale; + if(output->crtc) { + xf86CrtcPtr crtc = output->crtc; + + if(!xf86CrtcSetMode(crtc, &crtc->desiredMode, crtc->desiredRotation, + crtc->desiredX, crtc->desiredY)) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "Failed to set scaling to %s for output %s\n", + modes[i].name, output->name); + + // Restore old scale and try again. + pPriv->scale = oldScale; + if(!xf86CrtcSetMode(crtc, &crtc->desiredMode, + crtc->desiredRotation, crtc->desiredX, + crtc->desiredY)) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "Failed to restore old scaling for output %s\n", + output->name); + } + + return FALSE; + } + } + return TRUE; + } + + return FALSE; +} +#endif // RANDR_12_INTERFACE + +static const xf86OutputFuncsRec G80SorTMDSOutputFuncs = { + .dpms = G80SorDPMSSet, + .save = NULL, + .restore = NULL, + .mode_valid = G80TMDSModeValid, + .mode_fixup = G80SorTMDSModeFixup, + .prepare = G80OutputPrepare, + .commit = G80OutputCommit, + .mode_set = G80SorModeSet, + .detect = G80SorDetect, + .get_modes = G80OutputGetDDCModes, +#ifdef RANDR_12_INTERFACE + .create_resources = G80SorCreateResources, + .set_property = G80SorSetProperty, +#endif + .destroy = G80SorDestroy, +}; + +static const xf86OutputFuncsRec G80SorLVDSOutputFuncs = { + .dpms = G80SorDPMSSet, + .save = NULL, + .restore = NULL, + .mode_valid = G80LVDSModeValid, + .mode_fixup = G80SorModeFixup, + .prepare = G80OutputPrepare, + .commit = G80OutputCommit, + .mode_set = G80SorModeSet, + .detect = G80SorLVDSDetect, + .get_modes = G80SorGetLVDSModes, +#ifdef RANDR_12_INTERFACE + .create_resources = G80SorCreateResources, + .set_property = G80SorSetProperty, +#endif + .destroy = G80SorDestroy, +}; + +static DisplayModePtr +GetLVDSNativeMode(G80Ptr pNv) +{ + DisplayModePtr mode = xnfcalloc(1, sizeof(DisplayModeRec)); + const CARD32 size = pNv->reg[0x00610B4C/4]; + const int width = size & 0x3fff; + const int height = (size >> 16) & 0x3fff; + + mode->HDisplay = mode->CrtcHDisplay = width; + mode->VDisplay = mode->CrtcVDisplay = height; + mode->Clock = pNv->reg[0x610AD4/4] & 0x3fffff; + mode->CrtcHBlankStart = pNv->reg[0x610AFC/4]; + mode->CrtcHSyncEnd = pNv->reg[0x610B04/4]; + mode->CrtcHBlankEnd = pNv->reg[0x610AE8/4]; + mode->CrtcHTotal = pNv->reg[0x610AF4/4]; + + mode->next = mode->prev = NULL; + mode->status = MODE_OK; + mode->type = M_T_DRIVER | M_T_PREFERRED; + + xf86SetModeDefaultName(mode); + + return mode; +} + +xf86OutputPtr +G80CreateSor(ScrnInfoPtr pScrn, ORNum or, PanelType panelType) +{ + G80Ptr pNv = G80PTR(pScrn); + G80OutputPrivPtr pPriv = xnfcalloc(sizeof(*pPriv), 1); + const int off = 0x800 * or; + xf86OutputPtr output; + char orName[5]; + const xf86OutputFuncsRec *funcs; + + if(!pPriv) + return FALSE; + + if(panelType == LVDS) { + strcpy(orName, "LVDS"); + funcs = &G80SorLVDSOutputFuncs; + } else { + snprintf(orName, 5, "DVI%d", or); + pNv->reg[(0x61C00C+off)/4] = 0x03010700; + pNv->reg[(0x61C010+off)/4] = 0x0000152f; + pNv->reg[(0x61C014+off)/4] = 0x00000000; + pNv->reg[(0x61C018+off)/4] = 0x00245af8; + funcs = &G80SorTMDSOutputFuncs; + } + + output = xf86OutputCreate(pScrn, funcs, orName); + + pPriv->type = SOR; + pPriv->or = or; + pPriv->panelType = panelType; + pPriv->cached_status = XF86OutputStatusUnknown; + if(panelType == TMDS) + pPriv->set_pclk = G80SorSetPClk; + output->driver_private = pPriv; + output->interlaceAllowed = TRUE; + output->doubleScanAllowed = TRUE; + + if(panelType == LVDS) { + pPriv->nativeMode = GetLVDSNativeMode(pNv); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s native size %dx%d\n", + orName, pPriv->nativeMode->HDisplay, + pPriv->nativeMode->VDisplay); + } + + return output; +} diff --git a/driver/xf86-video-nv/src/g80_xaa.h b/driver/xf86-video-nv/src/g80_xaa.h index e2f1f63c5..6c1d7652f 100644 --- a/driver/xf86-video-nv/src/g80_xaa.h +++ b/driver/xf86-video-nv/src/g80_xaa.h @@ -1 +1,6 @@ +void G80Sync(ScrnInfoPtr pScrn); +void G80DMAKickoffCallback(ScrnInfoPtr pScrn); +void G80SetPattern(G80Ptr pNv, int bg, int fg, int pat0, int pat1); +void G80SetRopSolid(G80Ptr pNv, CARD32 rop, CARD32 planemask); +void G80SetClip(G80Ptr pNv, int x, int y, int w, int h); Bool G80XAAInit(ScreenPtr); diff --git a/driver/xf86-video-nv/src/local_xf86Rename.h b/driver/xf86-video-nv/src/local_xf86Rename.h new file mode 100644 index 000000000..f3a07c6b4 --- /dev/null +++ b/driver/xf86-video-nv/src/local_xf86Rename.h @@ -0,0 +1,23 @@ +/* + *Copyright © 2006 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#define XF86NAME(x) nv_##x diff --git a/driver/xf86-video-nv/src/riva_const.h b/driver/xf86-video-nv/src/riva_const.h index 4949fc124..890bcaaa6 100644 --- a/driver/xf86-video-nv/src/riva_const.h +++ b/driver/xf86-video-nv/src/riva_const.h @@ -1,5 +1,3 @@ -/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_const.h $ */ - #ifndef __RIVA_CONST_H__ #define __RIVA_CONST_H__ @@ -8,4 +6,3 @@ #define RIVA_DRIVER_NAME "riva128" #endif /* __RIVA_CONST_H__ */ - |