--- ../ati.orig/radeon_cursor.c 2003-05-20 13:47:34.000000000 -0400 +++ ./radeon_cursor.c 2003-06-21 10:51:23.000000000 -0400 @@ -89,6 +89,9 @@ #endif +static void +RADEONSetCursorPositionMerged(ScrnInfoPtr pScrn, int x, int y); + /* Set cursor foreground and background colors */ static void RADEONSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) { @@ -142,6 +145,11 @@ int Y2 = pScrn->frameY0 + y; int stride = 256; + if(info->MergedFB) { + RADEONSetCursorPositionMerged(pScrn, x, y); + return; + } + if (x < 0) xorigin = -x+1; if (y < 0) yorigin = -y+1; if (y > total_y) y = total_y; @@ -238,6 +246,59 @@ } } +static void +RADEONSetCursorPositionMerged(ScrnInfoPtr pScrn, int x, int y) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + xf86CursorInfoPtr cursor = info->cursor; + int xorigin = 0; + int yorigin = 0; + int stride = 256; + ScrnInfoPtr pScrn2 = info->CRT2pScrn; + DisplayModePtr mode1 = CDMPTR->CRT1; + DisplayModePtr mode2 = CDMPTR->CRT2; + int x1, y1, x2, y2; + + x += pScrn->frameX0; + y += pScrn->frameY0; + + x1 = x - info->CRT1frameX0; + y1 = y - info->CRT1frameY0; + + x2 = x - pScrn2->frameX0; + y2 = y - pScrn2->frameY0; + + if(mode1->Flags & V_INTERLACE) + y1 /= 2; + else if(mode1->Flags & V_DBLSCAN) + y1 *= 2; + + if(mode2->Flags & V_INTERLACE) + y2 /= 2; + else if(mode2->Flags & V_DBLSCAN) + y2 *= 2; + + /* cursor1 */ + OUTREG(RADEON_CUR_HORZ_VERT_OFF, (RADEON_CUR_LOCK + | (xorigin << 16) + | yorigin)); + OUTREG(RADEON_CUR_HORZ_VERT_POSN, (RADEON_CUR_LOCK + | ((xorigin ? 0 : x1) << 16) + | (yorigin ? 0 : y1))); + OUTREG(RADEON_CUR_OFFSET, info->cursor_start + yorigin * stride); + + /* cursor2 */ + OUTREG(RADEON_CUR2_HORZ_VERT_OFF, (RADEON_CUR2_LOCK + | (xorigin << 16) + | yorigin)); + OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK + | ((xorigin ? 0 : x2) << 16) + | (yorigin ? 0 : y2))); + OUTREG(RADEON_CUR2_OFFSET, + info->cursor_start + pScrn->fbOffset + yorigin * stride); +} + /* Copy cursor image from `image' to video memory. RADEONSetCursorPosition * will be called after this, so we can ignore xorigin and yorigin. */ @@ -259,7 +320,7 @@ OUTREG(RADEON_CRTC_GEN_CNTL, save1 & (CARD32)~RADEON_CRTC_CUR_EN); } - if (info->IsSecondary || info->Clone) { + if (info->IsSecondary || info->Clone || info->MergedFB) { save2 = INREG(RADEON_CRTC2_GEN_CNTL) & ~(CARD32) (3 << 20); save2 |= (CARD32) (2 << 20); OUTREG(RADEON_CRTC2_GEN_CNTL, save2 & (CARD32)~RADEON_CRTC2_CUR_EN); @@ -292,7 +353,7 @@ if (!info->IsSecondary) OUTREG(RADEON_CRTC_GEN_CNTL, save1); - if (info->IsSecondary || info->Clone) + if (info->IsSecondary || info->Clone || info->MergedFB) OUTREG(RADEON_CRTC2_GEN_CNTL, save2); } @@ -303,7 +364,7 @@ RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; - if (info->IsSecondary || info->Clone) + if (info->IsSecondary || info->Clone || info->MergedFB) OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_CUR_EN); if (!info->IsSecondary) @@ -316,7 +377,7 @@ RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; - if (info->IsSecondary || info->Clone) + if (info->IsSecondary || info->Clone || info->MergedFB) OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN, ~RADEON_CRTC2_CUR_EN); @@ -369,7 +430,7 @@ OUTREG(RADEON_CRTC_GEN_CNTL, save1 & (CARD32)~RADEON_CRTC_CUR_EN); } - if (info->IsSecondary || info->Clone) { + if (info->IsSecondary || info->Clone || info->MergedFB) { save2 = INREG(RADEON_CRTC2_GEN_CNTL) & ~(CARD32) (3 << 20); save2 |= (CARD32) (2 << 20); OUTREG(RADEON_CRTC2_GEN_CNTL, save2 & (CARD32)~RADEON_CRTC2_CUR_EN); @@ -407,7 +468,7 @@ if (!info->IsSecondary) OUTREG(RADEON_CRTC_GEN_CNTL, save1); - if (info->IsSecondary || info->Clone) + if (info->IsSecondary || info->Clone ||info->MergedFB) OUTREG(RADEON_CRTC2_GEN_CNTL, save2); } --- ../ati.orig/radeon_driver.c 2003-02-24 22:50:15.000000000 -0500 +++ radeon_driver.c 2003-07-13 18:56:02.000000000 -0400 @@ -115,6 +115,8 @@ static void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags); +Bool InRegion(int x, int y, region r); +void RADEONMergePointerMoved(int scrnIndex, int x, int y); typedef enum { OPTION_NOACCEL, @@ -141,7 +143,14 @@ OPTION_CLONE_HSYNC, OPTION_CLONE_VREFRESH, OPTION_FBDEV, - OPTION_VIDEO_KEY + OPTION_VIDEO_KEY, + OPTION_MERGEDFB, + OPTION_CRT2HSYNC, + OPTION_CRT2VREFRESH, + OPTION_CRT2POS, + OPTION_METAMODES, + OPTION_CRT2XV, + OPTION_MERGECRT2ON } RADEONOpts; const OptionInfoRec RADEONOptions[] = { @@ -170,6 +179,13 @@ { OPTION_CLONE_VREFRESH, "CloneVRefresh", OPTV_ANYSTR, {0}, FALSE }, { OPTION_FBDEV, "UseFBDev", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE }, + { OPTION_MERGEDFB, "MergedFB", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_CRT2HSYNC, "CRT2HSync", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_CRT2VREFRESH, "CRT2VRefresh", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_CRT2POS, "CRT2Position", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_METAMODES, "MetaModes", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_CRT2XV, "CRT2Xv", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_MERGECRT2ON, "CRT2ForceOn", OPTV_BOOLEAN, {0}, FALSE }, { -1, NULL, OPTV_NONE, {0}, FALSE } }; @@ -530,6 +546,48 @@ /* Free our private RADEONInfoRec */ static void RADEONFreeRec(ScrnInfoPtr pScrn) { + RADEONInfoPtr info = RADEONPTR(pScrn); + if(info->CRT2HSync) xfree(info->CRT2HSync); + info->CRT2HSync = NULL; + if(info->CRT2VRefresh) xfree(info->CRT2VRefresh); + info->CRT2VRefresh = NULL; + if(info->MetaModes) xfree(info->MetaModes); + info->MetaModes = NULL; + if(info->CRT2pScrn) { + if(info->CRT2pScrn->modes) { + while(info->CRT2pScrn->modes) + xf86DeleteMode(&info->CRT2pScrn->modes, info->CRT2pScrn->modes); + } + if(info->CRT2pScrn->monitor) { + if(info->CRT2pScrn->monitor->Modes) { + while(info->CRT2pScrn->monitor->Modes) + xf86DeleteMode(&info->CRT2pScrn->monitor->Modes, info->CRT2pScrn->monitor->Modes); + } + if(info->CRT2pScrn->monitor->DDC) xfree(info->CRT2pScrn->monitor->DDC); + xfree(info->CRT2pScrn->monitor); + } + xfree(info->CRT2pScrn); + info->CRT2pScrn = NULL; + } + if(info->CRT1Modes) { + if(info->CRT1Modes != pScrn->modes) { + if(pScrn->modes) { + pScrn->currentMode = pScrn->modes; + do { + DisplayModePtr p = pScrn->currentMode->next; + if(pScrn->currentMode->Private) + xfree(pScrn->currentMode->Private); + xfree(pScrn->currentMode); + pScrn->currentMode = p; + } while(pScrn->currentMode != pScrn->modes); + } + pScrn->currentMode = info->CRT1CurrentMode; + pScrn->modes = info->CRT1Modes; + info->CRT1CurrentMode = NULL; + info->CRT1Modes = NULL; + } + } + if (!pScrn || !pScrn->driverPrivate) return; xfree(pScrn->driverPrivate); pScrn->driverPrivate = NULL; @@ -723,7 +781,7 @@ default: break; } - if (info->Clone) + if (info->Clone || info->MergedFB) OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | @@ -764,7 +822,7 @@ default: break; } - if (info->Clone) + if (info->Clone || info->MergedFB) OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~(RADEON_CRTC2_DISP_DIS | @@ -805,6 +863,459 @@ return (n + (d / 2)) / d; } +/* mergedfb functions */ +/* Helper function for CRT2 monitor vrefresh/hsync options + * (Taken from mga driver) + */ +static int +RADEONStrToRanges(range *r, char *s) +{ + float num = 0.0; + int rangenum = 0; + Bool gotdash = FALSE; + Bool nextdash = FALSE; + char* strnum = NULL; + do { + switch(*s) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + if(strnum == NULL) { + strnum = s; + gotdash = nextdash; + nextdash = FALSE; + } + break; + case '-': + case ' ': + case 0: + if(strnum == NULL) break; + if(strnum != NULL) sscanf(strnum,"%f",&num); + if(gotdash) + r[rangenum - 1].hi = num; + else { + r[rangenum].lo = num; + r[rangenum].hi = num; + rangenum++; + } + strnum = NULL; + if(*s == '-') nextdash = (rangenum != 0); + break; + default : + return 0; + } + } while(*(s++) != 0); + + return rangenum; +} + +/* Copy and link two modes form merged-fb mode + * (Taken from mga driver) + * Copys mode i, links the result to dest, and returns it. + * Links i and j in Private record. + * If dest is NULL, return value is copy of i linked to itself. + */ +static DisplayModePtr +RADEONCopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest, + DisplayModePtr i, DisplayModePtr j, + RADEONScrn2Rel srel) +{ + DisplayModePtr mode; + int dx = 0,dy = 0; + + mode = xalloc(sizeof(DisplayModeRec)); + memcpy(mode, i, sizeof(DisplayModeRec)); + mode->Private = xalloc(sizeof(RADEONMergedDisplayModeRec)); + ((RADEONMergedDisplayModePtr)mode->Private)->CRT1 = i; + ((RADEONMergedDisplayModePtr)mode->Private)->CRT2 = j; + ((RADEONMergedDisplayModePtr)mode->Private)->CRT2Position = srel; + mode->PrivSize = 0; + + switch(srel) { + case radeonLeftOf: + case radeonRightOf: + dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay) - mode->HDisplay; + dy = min(pScrn->virtualY, max(i->VDisplay,j->VDisplay)) - mode->VDisplay; + break; + case radeonAbove: + case radeonBelow: + dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay) - mode->VDisplay; + dx = min(pScrn->virtualX, max(i->HDisplay,j->HDisplay)) - mode->HDisplay; + break; + case radeonClone: + dx = min(pScrn->virtualX, max(i->HDisplay,j->HDisplay)) - mode->HDisplay; + dy = min(pScrn->virtualY, max(i->VDisplay,j->VDisplay)) - mode->VDisplay; + break; + } + mode->HDisplay += dx; + mode->HSyncStart += dx; + mode->HSyncEnd += dx; + mode->HTotal += dx; + mode->VDisplay += dy; + mode->VSyncStart += dy; + mode->VSyncEnd += dy; + mode->VTotal += dy; + mode->Clock = 0; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Merged %dx%d and %dx%d to %dx%d (Virtual %d %d)\n", + i->HDisplay, i->VDisplay, j->HDisplay, j->VDisplay, + mode->HDisplay, mode->VDisplay, + pScrn->virtualX, pScrn->virtualY); + + mode->next = mode; + mode->prev = mode; + + if(dest) { + mode->next = dest->next; /* Insert node after "dest" */ + dest->next->prev = mode; + mode->prev = dest; + dest->next = mode; + } + + return mode; +} + +/* Helper function to find a mode from a given name + * (Taken from mga driver) + */ +static DisplayModePtr +RADEONGetModeFromName(char* str, DisplayModePtr i) +{ + DisplayModePtr c = i; + if(!i) return NULL; + do { + if(strcmp(str, c->name) == 0) return c; + c = c->next; + } while(c != i); + return NULL; +} + +/* Generate the merged-fb mode modelist + * (Taken from mga driver) + */ +static DisplayModePtr +RADEONGenerateModeList(ScrnInfoPtr pScrn, char* str, + DisplayModePtr i, DisplayModePtr j, + RADEONScrn2Rel srel) +{ + char* strmode = str; + char modename[256]; + Bool gotdash = FALSE; + RADEONScrn2Rel sr; + + DisplayModePtr mode1 = NULL; + DisplayModePtr mode2 = NULL; + DisplayModePtr result = NULL; + do { + switch(*str) { + case 0: + case '-': + case ' ': + if((strmode != str)) { + + strncpy(modename, strmode, str - strmode); + modename[str - strmode] = 0; + + if(gotdash) { + if(mode1 == NULL) return NULL; + mode2 = RADEONGetModeFromName(modename, j); + if(!mode2) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Mode \"%s\" is not a supported mode for CRT2\n", modename); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Skipping metamode \"%s-%s\".\n", mode1->name, modename); + mode1 = NULL; + } + } else { + mode1 = RADEONGetModeFromName(modename, i); + if(!mode1) { + char* tmps = str; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Mode \"%s\" is not a supported mode for CRT1\n", modename); + gotdash = FALSE; + while(*tmps == ' ') tmps++; + if(*tmps == '-') { /* skip the next mode */ + tmps++; + while((*tmps == ' ') && (*tmps != 0)) tmps++; /* skip spaces */ + while((*tmps != ' ') && (*tmps != '-') && (*tmps != 0)) tmps++; /* skip modename */ + strncpy(modename,strmode,tmps - strmode); + modename[tmps - strmode] = 0; + str = tmps-1; + } + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Skipping metamode \"%s\".\n", modename); + mode1 = NULL; + } + } + gotdash = FALSE; + } + strmode = str + 1; + gotdash |= (*str == '-'); + + if(*str != 0) break; + /* Fall through otherwise */ + + default: + if(!gotdash && mode1) { + sr = srel; + if(!mode2) { + mode2 = RADEONGetModeFromName(mode1->name, j); + sr = radeonClone; + } + if(!mode2) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Mode: \"%s\" is not a supported mode for CRT2\n", mode1->name); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Skipping metamode \"%s\".\n"); + mode1 = NULL; + } else { + result = RADEONCopyModeNLink(pScrn, result, mode1, mode2, sr); + mode1 = NULL; + mode2 = NULL; + } + } + break; + + } + + } while(*(str++) != 0); + + return result; +} + +Bool +InRegion(int x, int y, region r) +{ + return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1); +} + +void +RADEONMergePointerMoved(int scrnIndex, int x, int y) +{ + ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn1); + ScrnInfoPtr pScrn2 = info->CRT2pScrn; + region out, in1, in2, f2, f1; + int deltax, deltay; + + f1.x0 = info->CRT1frameX0; + f1.x1 = info->CRT1frameX1; + f1.y0 = info->CRT1frameY0; + f1.y1 = info->CRT1frameY1; + f2.x0 = pScrn2->frameX0; + f2.x1 = pScrn2->frameX1; + f2.y0 = pScrn2->frameY0; + f2.y1 = pScrn2->frameY1; + + /* Define the outer region. Crossing this causes all frames to move */ + out.x0 = pScrn1->frameX0; + out.x1 = pScrn1->frameX1; + out.y0 = pScrn1->frameY0; + out.y1 = pScrn1->frameY1; + + /* + * Define the inner sliding window. Being outsize both frames but + * inside the outer clipping window will slide corresponding frame + */ + in1 = out; + in2 = out; + switch(((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position) { + case radeonLeftOf: + in1.x0 = f1.x0; + in2.x1 = f2.x1; + break; + case radeonRightOf: + in1.x1 = f1.x1; + in2.x0 = f2.x0; + break; + case radeonBelow: + in1.y1 = f1.y1; + in2.y0 = f2.y0; + break; + case radeonAbove: + in1.y0 = f1.y0; + in2.y1 = f2.y1; + break; + case radeonClone: + break; + } + + deltay = 0; + deltax = 0; + + if(InRegion(x, y, out)) { /* inside outer region */ + + /* xf86DrvMsg(0, X_INFO, "1: %d %d | %d %d %d %d | %d %d %d %d\n", + x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); */ + + if(InRegion(x, y, in1) && !InRegion(x, y, f1)) { + REBOUND(f1.x0, f1.x1, x); + REBOUND(f1.y0, f1.y1, y); + deltax = 1; + /* xf86DrvMsg(0, X_INFO, "2: %d %d | %d %d %d %d | %d %d %d %d\n", + x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); */ + } + if(InRegion(x, y, in2) && !InRegion(x, y, f2)) { + REBOUND(f2.x0, f2.x1, x); + REBOUND(f2.y0, f2.y1, y); + deltax = 1; + } + + } else { /* outside outer region */ + + /* xf86DrvMsg(0, X_INFO, "3: %d %d | %d %d %d %d | %d %d %d %d\n", + x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); + xf86DrvMsg(0, X_INFO, "3-out: %d %d %d %d\n", + out.x0, out.x1, out.y0, out.y1); */ + + if(out.x0 > x) { + deltax = x - out.x0; + } + if(out.x1 < x) { + deltax = x - out.x1; + } + if(deltax) { + pScrn1->frameX0 += deltax; + pScrn1->frameX1 += deltax; + f1.x0 += deltax; + f1.x1 += deltax; + f2.x0 += deltax; + f2.x1 += deltax; + } + + if(out.y0 > y) { + deltay = y - out.y0; + } + if(out.y1 < y) { + deltay = y - out.y1; + } + if(deltay) { + pScrn1->frameY0 += deltay; + pScrn1->frameY1 += deltay; + f1.y0 += deltay; + f1.y1 += deltay; + f2.y0 += deltay; + f2.y1 += deltay; + } + + switch(((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position) { + case radeonLeftOf: + if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); } + if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); } + break; + case radeonRightOf: + if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); } + if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); } + break; + case radeonBelow: + if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); } + if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); } + break; + case radeonAbove: + if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); } + if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); } + break; + case radeonClone: + break; + } + + } + + if(deltax || deltay) { + info->CRT1frameX0 = f1.x0; + info->CRT1frameY0 = f1.y0; + pScrn2->frameX0 = f2.x0; + pScrn2->frameY0 = f2.y0; + + info->CRT1frameX1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1; + info->CRT1frameY1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1; + pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay - 1; + pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay - 1; + pScrn1->frameX1 = pScrn1->frameX0 + info->CurrentLayout.mode->HDisplay - 1; + pScrn1->frameY1 = pScrn1->frameY0 + info->CurrentLayout.mode->VDisplay - 1; + + RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); + RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); + } +} + +static void +RADEONAdjustFrameMerged(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn1); + ScrnInfoPtr pScrn2 = info->CRT2pScrn; + int VTotal = info->CurrentLayout.mode->VDisplay; + int HTotal = info->CurrentLayout.mode->HDisplay; + int VMax = VTotal; + int HMax = HTotal; + + BOUND(x, 0, pScrn1->virtualX - HTotal); + BOUND(y, 0, pScrn1->virtualY - VTotal); + + switch(SDMPTR(pScrn1)->CRT2Position) { + case radeonLeftOf: + pScrn2->frameX0 = x; + BOUND(pScrn2->frameY0, y, y + VMax - CDMPTR->CRT2->VDisplay); + info->CRT1frameX0 = x + CDMPTR->CRT2->HDisplay; + BOUND(info->CRT1frameY0, y, y + VMax - CDMPTR->CRT1->VDisplay); + break; + case radeonRightOf: + info->CRT1frameX0 = x; + BOUND(info->CRT1frameY0, y, y + VMax - CDMPTR->CRT1->VDisplay); + pScrn2->frameX0 = x + CDMPTR->CRT1->HDisplay; + BOUND(pScrn2->frameY0, y, y + VMax - CDMPTR->CRT2->VDisplay); + break; + case radeonAbove: + BOUND(pScrn2->frameX0, x, x + HMax - CDMPTR->CRT2->HDisplay); + pScrn2->frameY0 = y; + BOUND(info->CRT1frameX0, x, x + HMax - CDMPTR->CRT1->HDisplay); + info->CRT1frameY0 = y + CDMPTR->CRT2->VDisplay; + break; + case radeonBelow: + BOUND(info->CRT1frameX0, x, x + HMax - CDMPTR->CRT1->HDisplay); + info->CRT1frameY0 = y; + BOUND(pScrn2->frameX0, x, x + HMax - CDMPTR->CRT2->HDisplay); + pScrn2->frameY0 = y + CDMPTR->CRT1->VDisplay; + break; + case radeonClone: + BOUND(info->CRT1frameX0, x, x + HMax - CDMPTR->CRT1->HDisplay); + BOUND(info->CRT1frameY0, y, y + VMax - CDMPTR->CRT1->VDisplay); + BOUND(pScrn2->frameX0, x, x + HMax - CDMPTR->CRT2->HDisplay); + BOUND(pScrn2->frameY0, y, y + VMax - CDMPTR->CRT2->VDisplay); + break; + } + + BOUND(info->CRT1frameX0, 0, pScrn1->virtualX - CDMPTR->CRT1->HDisplay); + BOUND(info->CRT1frameY0, 0, pScrn1->virtualY - CDMPTR->CRT1->VDisplay); + BOUND(pScrn2->frameX0, 0, pScrn1->virtualX - CDMPTR->CRT2->HDisplay); + BOUND(pScrn2->frameY0, 0, pScrn1->virtualY - CDMPTR->CRT2->VDisplay); + + pScrn1->frameX0 = x; + pScrn1->frameY0 = y; + + info->CRT1frameX1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1; + info->CRT1frameY1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1; + pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay - 1; + pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay - 1; + pScrn1->frameX1 = pScrn1->frameX0 + info->CurrentLayout.mode->HDisplay - 1; + pScrn1->frameY1 = pScrn1->frameY0 + info->CurrentLayout.mode->VDisplay - 1; + + RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); + RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); +} + +/* End of MergedFB helpers */ + /* Read the Video BIOS block and the FP registers (if applicable) */ static Bool RADEONGetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) { @@ -813,6 +1324,8 @@ unsigned char *RADEONMMIO; Bool BypassSecondary = FALSE; int CloneDispOption; + Bool CRT2XVOption; + Bool CRT2OnOption; #define RADEON_BIOS8(v) (info->VBIOS[v]) #define RADEON_BIOS16(v) (info->VBIOS[v] | \ @@ -900,6 +1413,8 @@ } else { info->Clone = FALSE; info->CloneType = MT_NONE; + /* info->MergedFB = FALSE; */ + info->MergeType = MT_NONE; /* Check Primary (DVI/DFP port) */ if (tmp & 0x08) info->DisplayType = MT_DFP; @@ -938,12 +1453,30 @@ if (tmp & 0x02) { info->CloneType = MT_CRT; info->Clone = TRUE; + info->MergeType = MT_CRT; + /* info->MergedFB = TRUE; */ } else if (tmp & 0x800) { info->CloneType = MT_DFP; info->Clone = TRUE; + info->MergeType = MT_DFP; + /* info->MergedFB = TRUE; */ } } + xf86GetOptValBool(info->Options, OPTION_CRT2XV, + &(CRT2XVOption)); + xf86GetOptValBool(info->Options, OPTION_MERGECRT2ON, + &(CRT2OnOption)); + if (info->MergedFB) { + info->Clone = FALSE; + info->CurCloneMode = NULL; + if (CRT2XVOption) + info->OverlayOnCRTC2 = TRUE; + /* should auto-detect above, if not, un-comment this to force CRT */ + if (CRT2OnOption) + info->MergeType = MT_CRT; + } + /* FIXME: This option is too complicated. We need to * find a better way to handle all cases. * @@ -968,6 +1501,7 @@ * on the other head will be blank). 2nd head overlay is on * automatically when PanelOff option is effective. */ + if (!info->MergedFB) { if (xf86GetOptValInteger(info->Options, OPTION_CLONE_DISPLAY, &(CloneDispOption))) { char *s = NULL; @@ -1009,6 +1543,8 @@ if (info->Clone && (CloneDispOption == 3 || CloneDispOption == 4)) info->OverlayOnCRTC2 = TRUE; } + } + } else { /* Regular Radeon ASIC, only one CRTC, but it could be used for * DFP with a DVI output, like AIW board @@ -1147,6 +1683,7 @@ else info->DDCType = DDC_DVI; info->CloneDDCType = DDC_CRT2; + info->MergeDDCType = DDC_CRT2; } else if ((tmp = RADEON_BIOS16(info->FPBIOSstart + 0x50))) { for (i = 1; i < 4; i++) { unsigned int tmp0; @@ -1160,6 +1697,8 @@ } else { /* Primary DAC */ if (info->Clone) info->CloneDDCType = (tmp0 & 0x0f00) >> 8; + else if (info->MergedFB) + info->MergeDDCType = (tmp0 & 0x0f00) >> 8; else if (info->IsSecondary || BypassSecondary || !info->HasCRTC2) { @@ -1539,6 +2078,7 @@ info->LinearAddr += pScrn->videoRam * 1024; info1->Clone = FALSE; info1->CurCloneMode = NULL; + info1->MergedFB = FALSE; } info->R300CGWorkaround = @@ -2711,6 +3251,238 @@ return modesFound; } +static int RADEONValidateMergeModes(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + ClockRangePtr clockRanges; + DisplayModePtr tmp_mode = NULL; + DisplayModePtr merge_mode, save_mode; + int modesFound = 0; + int count = 0; + int tmp_hdisplay = 0; + int tmp_vdisplay = 0; + int i, save_n_hsync, save_n_vrefresh; + range save_hsync, save_vrefresh; + char *s; + char **merge_mode_names = NULL; + Bool ddc_mode = info->ddc_mode; + + /* Save all infomations that will be changed by clone mode validateion */ + save_mode = pScrn->modes; + pScrn->modes = NULL; + + /* Clone display mode names, duplicate all mode names for primary + * head. Allocate one more, in case pScrn->display->modes[0] == + * NULL */ + while (pScrn->display->modes[count]) count++; + merge_mode_names = xnfalloc((count+2) * sizeof(char*)); + for (i = 0; i < count; i++) { + merge_mode_names[i] = xnfalloc(strlen(pScrn->display->modes[i]) + 1); + strcpy(merge_mode_names[i], pScrn->display->modes[i]); + } + merge_mode_names[count] = NULL; + merge_mode_names[count+1] = NULL; + + pScrn->progClock = TRUE; + + clockRanges = xnfcalloc(sizeof(*clockRanges), 1); + clockRanges->next = NULL; + clockRanges->minClock = info->pll.min_pll_freq; + clockRanges->maxClock = info->pll.max_pll_freq * 10; + clockRanges->clockIndex = -1; + clockRanges->interlaceAllowed = FALSE; + clockRanges->doubleScanAllowed = FALSE; + + if (pScrn->display->virtualX < tmp_hdisplay) + pScrn->display->virtualX = tmp_hdisplay; + if (pScrn->display->virtualY < tmp_vdisplay) + pScrn->display->virtualY = tmp_vdisplay; + + save_hsync = pScrn->monitor->hsync[0]; + save_vrefresh = pScrn->monitor->vrefresh[0]; + save_n_hsync = pScrn->monitor->nHsync; + save_n_vrefresh = pScrn->monitor->nVrefresh; + + pScrn->monitor->DDC = NULL; + pScrn->monitor->nHsync = 0; + pScrn->monitor->nVrefresh = 0; + + if ((s = xf86GetOptValString(info->Options, OPTION_CRT2HSYNC))) { + if (sscanf(s, "%f-%f", &pScrn->monitor->hsync[0].lo, + &pScrn->monitor->hsync[0].hi) == 2) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "HSync for MergedFB Mode from config file: %s\n", s); + pScrn->monitor->nHsync = 1; + } else { + pScrn->monitor->nHsync = 0; + } + } + + if ((s = xf86GetOptValString(info->Options, OPTION_CRT2VREFRESH))) { + if (sscanf(s, "%f-%f", &pScrn->monitor->vrefresh[0].lo, + &pScrn->monitor->vrefresh[0].hi) == 2) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "VRefresh for MergedFB Mode from config file: %s\n", s); + pScrn->monitor->nVrefresh = 1; + } else { + pScrn->monitor->nVrefresh = 0; + } + } + + if ((pScrn->monitor->nVrefresh == 0) || (pScrn->monitor->nHsync == 0) || + (info->MergeType != MT_CRT) || info->ddc_mode) { + unsigned int save_ddc_reg; + save_ddc_reg = info->DDCReg; + switch (info->MergeDDCType) { + case DDC_MONID: info->DDCReg = RADEON_GPIO_MONID; break; + case DDC_DVI: info->DDCReg = RADEON_GPIO_DVI_DDC; break; + case DDC_VGA: info->DDCReg = RADEON_GPIO_VGA_DDC; break; + case DDC_CRT2: info->DDCReg = RADEON_GPIO_CRT2_DDC; break; + default: info->DDCReg = 0; break; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "DDC detection (type %d) for MergedFB modes\n", + info->MergeDDCType); + + /* When primary head has an invalid DDC type, I2C is not + * initialized, so we do it here. + */ + if (!info->ddc2) info->ddc2 = xf86I2CBusInit(info->pI2CBus); + + /* copy DDC into CRT2pScrn for setting dpi later */ + info->CRT2pScrn->monitor->DDC = RADEONDoDDC(pScrn, NULL); + pScrn->monitor->DDC = RADEONDoDDC(pScrn, NULL); + if (pScrn->monitor->DDC) { + if (info->MergeType == MT_CRT) { + if (pScrn->monitor->nHsync == 0) + RADEONSetSyncRangeFromEdid(pScrn, 1); + if (pScrn->monitor->nVrefresh == 0) + RADEONSetSyncRangeFromEdid(pScrn, 0); + } + } else if (info->ddc_mode) { + ddc_mode = FALSE; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No DDC data available for MergedFB mode, " + "DDCMode option is dismissed\n"); + } + info->DDCReg = save_ddc_reg; + } + + if (info->MergeType == MT_CRT && !ddc_mode) { + modesFound = + xf86ValidateModes(pScrn, pScrn->monitor->Modes, + merge_mode_names, + clockRanges, + NULL, /* linePitches */ + 8 * 64, /* minPitch */ + 8 * 1024, /* maxPitch */ + 64 * pScrn->bitsPerPixel, /* pitchInc */ + 128, /* minHeight */ + 2048, /* maxHeight */ + pScrn->display->virtualX, + pScrn->display->virtualY, + info->FbMapSize, + LOOKUP_BEST_REFRESH); + } else { + /* Try to add DDC modes */ + info->IsSecondary = TRUE; /* Fake it */ + modesFound = RADEONValidateDDCModes(pScrn, merge_mode_names, + info->MergeType); + info->IsSecondary = FALSE; /* Restore it!!! */ + + /* If that fails and we're connect to a flat panel, then try to + * add the flat panel modes + */ + if (modesFound < 1 && info->DisplayType != MT_CRT) + modesFound = RADEONValidateFPModes(pScrn, merge_mode_names); + } + + /* copy modes to CRT2pScrn */ + info->CRT2pScrn->modes = pScrn->modes; + /* probably need mm for DPI later */ + info->CRT2pScrn->monitor->widthmm = pScrn->monitor->widthmm; + info->CRT2pScrn->monitor->heightmm = pScrn->monitor->heightmm; + info->CRT2pScrn->monitor->hsync[0] = pScrn->monitor->hsync[0]; + info->CRT2pScrn->monitor->vrefresh[0] = pScrn->monitor->vrefresh[0]; + info->CRT2pScrn->monitor->nHsync = pScrn->monitor->nHsync; + info->CRT2pScrn->monitor->nVrefresh = pScrn->monitor->nVrefresh; + info->CRT2pScrn->display->virtualX = pScrn->display->virtualX; + info->CRT2pScrn->display->virtualY = pScrn->display->virtualY; + info->CRT2pScrn->virtualX = pScrn->virtualX; + info->CRT2pScrn->virtualY = pScrn->virtualY; + RADEONSetPitch(info->CRT2pScrn); + + if (modesFound > 0) { + xf86SetCrtcForModes(info->CRT2pScrn, INTERLACE_HALVE_V); /* 0); */ + xf86PrintModes(info->CRT2pScrn); + for (i = 0; i < modesFound; i++) { + while (info->CRT2pScrn->modes->status != MODE_OK) { + info->CRT2pScrn->modes = info->CRT2pScrn->modes->next; + } + if (!pScrn->modes) break; + + merge_mode = xnfcalloc (1, sizeof (DisplayModeRec)); + if (!merge_mode || !info->CRT2pScrn->modes) break; + memcpy(merge_mode, info->CRT2pScrn->modes, sizeof(DisplayModeRec)); + merge_mode->name = xnfalloc(strlen(info->CRT2pScrn->modes->name) + 1); + strcpy(merge_mode->name, info->CRT2pScrn->modes->name); + + /* this might not be necessary */ + if (i == 0) { + info->CRT2pScrn->modes = merge_mode; + info->CRT2pScrn->currentMode = merge_mode; + } else { + merge_mode->prev = tmp_mode; + merge_mode->prev->next = merge_mode; + } + + tmp_mode = merge_mode; + merge_mode->next = NULL; + info->CRT2pScrn->modes = pScrn->modes->next; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Valid MergedFB Mode: %s\n", merge_mode->name); + } + } + + /* merge_mode_names list is no longer needed, free it. */ + if (merge_mode_names) { + for (i = 0; merge_mode_names[i]; i++) { + free(merge_mode_names[i]); + merge_mode_names[i] = NULL; + } + + free(merge_mode_names); + merge_mode_names = NULL; + } + + /* We need to restore all changed info for the primary head */ + pScrn->modes = save_mode; + + pScrn->monitor->hsync[0] = save_hsync; + pScrn->monitor->vrefresh[0] = save_vrefresh; + pScrn->monitor->nHsync = save_n_hsync; + pScrn->monitor->nVrefresh = save_n_vrefresh; + + /* + * Also delete the clockRanges (if it was setup) since it will be + * set up during the primary head initialization. + */ + while (pScrn->clockRanges) { + ClockRangesPtr CRtmp = pScrn->clockRanges; + pScrn->clockRanges = pScrn->clockRanges->next; + xfree(CRtmp); + } + + /* modePool is no longer needed, free it */ + while (pScrn->modePool) + xf86DeleteMode(&pScrn->modePool, pScrn->modePool); + pScrn->modePool = NULL; + + return modesFound; +} + + /* This is called by RADEONPreInit to validate modes and compute * parameters for all of the valid modes. */ @@ -2792,6 +3564,32 @@ modesFound); } } + if (info->MergedFB) { + DevUnion *pPriv; + RADEONEntPtr pRADEONEnt; + pPriv = xf86GetEntityPrivate(pScrn->entityList[0], + gRADEONEntityIndex); + pRADEONEnt = pPriv->ptr; + + /* If we have 2 screens from the config file, we don't need + * to do merge thing, let each screen handles one head. + */ + if (!pRADEONEnt->HasSecondary) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "CRT2 modes validation ------------ \n"); + + modesFound = RADEONValidateMergeModes(pScrn); + if (modesFound < 1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid mode found for CRTC2\n"); + info->MergedFB = FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Total of %d MergedFB modes found ------------ \n\n", + modesFound); + } + } + } xf86DrvMsg(pScrn->scrnIndex, X_INFO, @@ -2926,11 +3724,72 @@ } pScrn->currentMode = pScrn->modes; + if(info->MergedFB) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Modes for CRT1: ********************\n"); + } xf86PrintModes(pScrn); + if(info->MergedFB) { + + /* xf86SetCrtcForModes(info->CRT2pScrn, INTERLACE_HALVE_V); */ + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Modes for CRT2: ********************\n"); + + xf86PrintModes(info->CRT2pScrn); + + info->CRT1Modes = pScrn->modes; + info->CRT1CurrentMode = pScrn->currentMode; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Generating MergedFB mode list\n"); + + pScrn->modes = RADEONGenerateModeList(pScrn, info->MetaModes, + info->CRT1Modes, info->CRT2pScrn->modes, + info->CRT2Position); + + if(!pScrn->modes) { + + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to parse MetaModes or no modes found. MergeFB mode disabled.\n"); + if(info->CRT2pScrn) { + if(info->CRT2pScrn->modes) { + while(info->CRT2pScrn->modes) + xf86DeleteMode(&info->CRT2pScrn->modes, info->CRT2pScrn->modes); + } + if(info->CRT2pScrn->monitor) { + if(info->CRT2pScrn->monitor->Modes) { + while(info->CRT2pScrn->monitor->Modes) + xf86DeleteMode(&info->CRT2pScrn->monitor->Modes, info->CRT2pScrn->monitor->Modes); + } + if(info->CRT2pScrn->monitor->DDC) xfree(info->CRT2pScrn->monitor->DDC); + xfree(info->CRT2pScrn->monitor); + } + xfree(info->CRT2pScrn); + } + pScrn->modes = info->CRT1Modes; + info->CRT1Modes = NULL; + info->MergedFB = FALSE; + + } else { + + pScrn->modes = pScrn->modes->next; + pScrn->currentMode = pScrn->modes; +#if 0 + /* TW: Update CurrentLayout */ + info->CurrentLayout.mode = pScrn->currentMode; + info->CurrentLayout.displayWidth = pScrn->displayWidth; +#endif + } + } + /* Set DPI */ xf86SetDpi(pScrn, 0, 0); - +#if 1 + if(info->MergedFB) { + xf86SetDpi(info->CRT2pScrn, 0, 0); + } +#endif /* Get ScreenInit function */ #ifdef USE_FB mod = "fb"; @@ -3170,6 +4029,7 @@ RADEONInfoPtr info; xf86Int10InfoPtr pInt10 = NULL; void *int10_save = NULL; + char *strptr; RADEONTRACE(("RADEONPreInit\n")); if (pScrn->numEntities != 1) return FALSE; @@ -3182,6 +4042,7 @@ info->CurCloneMode = NULL; info->CloneModes = NULL; info->IsSwitching = FALSE; + info->MergedFB = FALSE; info->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); if (info->pEnt->location.type != BUS_PCI) goto fail; @@ -3318,12 +4179,93 @@ RADEONPostInt10Check(pScrn, int10_save); + /* collect MergedFB options */ + xf86GetOptValBool(info->Options, OPTION_MERGEDFB,&(info->MergedFB)); + + /* TW: Do some MergedFB mode initialisation */ + if(info->MergedFB) { + info->CRT2pScrn = xalloc(sizeof(ScrnInfoRec)); + if(!info->CRT2pScrn) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate memory for merged pScrn, MergedFB mode is disabled\n"); + info->MergedFB = FALSE; + } else { + memcpy(info->CRT2pScrn, pScrn, sizeof(ScrnInfoRec)); + } + } + if(info->MergedFB) { + strptr = (char *)xf86GetOptValString(info->Options, OPTION_CRT2POS); + if(strptr) { + if((!strcmp(strptr,"LeftOf")) || (!strcmp(strptr,"leftof"))) + info->CRT2Position = radeonLeftOf; + else if((!strcmp(strptr,"RightOf")) || (!strcmp(strptr,"rightof"))) + info->CRT2Position = radeonRightOf; + else if((!strcmp(strptr,"Above")) || (!strcmp(strptr,"above"))) + info->CRT2Position = radeonAbove; + else if((!strcmp(strptr,"Below")) || (!strcmp(strptr,"below"))) + info->CRT2Position = radeonBelow; + else if((!strcmp(strptr,"Clone")) || (!strcmp(strptr,"clone"))) + info->CRT2Position = radeonClone; + else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "\"%s\" is not a valid parameter for Option \"CRT2Position\"\n", strptr); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Valid parameters are \"RightOf\", \"LeftOf\", \"Above\", \"Below\", or \"Clone\"\n"); + } + } + strptr = (char *)xf86GetOptValString(info->Options, OPTION_METAMODES); + if(strptr) { + info->MetaModes = xalloc(strlen(strptr) + 1); + if(info->MetaModes) memcpy(info->MetaModes, strptr, strlen(strptr) + 1); + } + if(info->MetaModes) { + strptr = (char *)xf86GetOptValString(info->Options, OPTION_CRT2HSYNC); + if(strptr) { + info->CRT2HSync = xalloc(strlen(strptr) + 1); + if(info->CRT2HSync) memcpy(info->CRT2HSync, strptr, strlen(strptr) + 1); + } + strptr = (char *)xf86GetOptValString(info->Options, OPTION_CRT2VREFRESH); + if(strptr) { + info->CRT2VRefresh = xalloc(strlen(strptr) + 1); + if(info->CRT2VRefresh) memcpy(info->CRT2VRefresh, strptr, strlen(strptr) + 1); + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Option \"MergedFB\" requires Option \"MetaModes\".\n"); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "MergedFB mode disabled.\n"); + info->MergedFB = FALSE; + } + } + + if(info->MergedFB) { + info->CRT2pScrn->monitor = xalloc(sizeof(MonRec)); + if(info->CRT2pScrn->monitor) { + memcpy(info->CRT2pScrn->monitor, pScrn->monitor, sizeof(MonRec)); + info->CRT2pScrn->monitor->DDC = NULL; + info->CRT2pScrn->monitor->Modes = NULL; + if(info->CRT2HSync) { + info->CRT2pScrn->monitor->nHsync = + RADEONStrToRanges(info->CRT2pScrn->monitor->hsync, info->CRT2HSync); + } + if(info->CRT2VRefresh) { + info->CRT2pScrn->monitor->nVrefresh = + RADEONStrToRanges(info->CRT2pScrn->monitor->vrefresh, info->CRT2VRefresh); + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate memory for CRT2 monitor, MergedFB mode disabled.\n"); + if(info->CRT2pScrn) xfree(info->CRT2pScrn); + info->CRT2pScrn = NULL; + info->MergedFB = FALSE; + } + } + if (!RADEONPreInitConfig(pScrn)) - goto fail; + goto fail; #if !defined(__powerpc__) if (!RADEONGetBIOSParameters(pScrn, pInt10)) - goto fail; + goto fail; #else /* Force type to CRT since we currently can't read BIOS to tell us * what kind of heads we have. @@ -3456,7 +4398,7 @@ } } - if (info->Clone) { + if (info->Clone || info->MergedFB) { PAL_SELECT(1); if (info->CurrentLayout.depth == 15) { /* 15bpp mode. This sends 32 values. */ @@ -3572,7 +4514,11 @@ RADEONSaveScreen(pScreen, SCREEN_SAVER_ON); pScrn->AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); - +#if 0 + if (info->MergedFB) + RADEONDoAdjustFrame(info->CRT2pScrn, info->CRT2pScrn->frameX0, + info->CRT2pScrn->frameY0, TRUE); +#endif if (info->CurCloneMode) { info->CloneFrameX0 = (pScrn->virtualX - info->CurCloneMode->HDisplay) / 2; @@ -4044,6 +4990,14 @@ RADEONInitVideo(pScreen); + /* Wrap some funcs */ + if(info->MergedFB) { + info->PointerMoved = pScrn->PointerMoved; + pScrn->PointerMoved = RADEONMergePointerMoved; + /* info->Rotate = FALSE; + info->ShadowFB = FALSE; */ + } + /* Provide SaveScreen */ pScreen->SaveScreen = RADEONSaveScreen; @@ -4111,7 +5065,7 @@ pPriv = xf86GetEntityPrivate(pScrn->entityList[0], gRADEONEntityIndex); pRADEONEnt = pPriv->ptr; - if (pRADEONEnt->HasSecondary || info->Clone) { + if (pRADEONEnt->HasSecondary || info->Clone || info->MergedFB) { tmp = INREG(RADEON_DAC_CNTL2); OUTREG(RADEON_DAC_CNTL2, tmp & ~RADEON_DAC2_DAC_CLK_SEL); usleep(100000); @@ -4210,7 +5164,8 @@ OUTREG(RADEON_CRTC2_OFFSET_CNTL, restore->crtc2_offset_cntl); OUTREG(RADEON_CRTC2_PITCH, restore->crtc2_pitch); - if (info->DisplayType == MT_DFP || info->CloneType == MT_DFP) { + if (info->DisplayType == MT_DFP || info->CloneType == MT_DFP + || info->MergeType == MT_DFP) { OUTREG(RADEON_FP_H2_SYNC_STRT_WID, restore->fp2_h_sync_strt_wid); OUTREG(RADEON_FP_V2_SYNC_STRT_WID, restore->fp2_v_sync_strt_wid); OUTREG(RADEON_FP2_GEN_CNTL, restore->fp2_gen_cntl); @@ -4543,6 +5498,10 @@ RADEONRestoreCrtc2Registers(pScrn, restore); RADEONRestorePLL2Registers(pScrn, restore); } + if (info->MergedFB) { + RADEONRestoreCrtc2Registers(pScrn, restore); + RADEONRestorePLL2Registers(pScrn, restore); + } if (!pRADEONEnt->HasSecondary || pRADEONEnt->IsSecondaryRestored || info->IsSwitching) { @@ -4745,6 +5704,11 @@ RADEONSaveCrtc2Registers(pScrn, save); RADEONSavePLL2Registers(pScrn, save); } + if (info->MergedFB) { + RADEONSaveCrtc2Registers(pScrn, save); + RADEONSavePLL2Registers(pScrn, save); + } + /* RADEONSavePalette(pScrn, save); */ } @@ -5091,7 +6055,8 @@ } else { save->disp_hw_debug = info->SavedReg.disp_hw_debug; if (info->IsDell && info->DellType == 2) { - if (info->DisplayType == MT_CRT || info->CloneType == MT_CRT) { + if (info->DisplayType == MT_CRT || info->CloneType == MT_CRT + || info->MergeType == MT_CRT) { /* Turn on 2nd CRT */ save->dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; save->dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; @@ -5145,12 +6110,21 @@ save->crtc2_offset = 0; save->crtc2_offset_cntl = INREG(RADEON_CRTC2_OFFSET_CNTL); - save->crtc2_pitch = (((pScrn->displayWidth * pScrn->bitsPerPixel) + + /* this should be right */ + if (info->MergedFB) { + save->crtc2_pitch = (((info->CRT2pScrn->displayWidth * pScrn->bitsPerPixel) + ((pScrn->bitsPerPixel * 8) -1)) / (pScrn->bitsPerPixel * 8)); save->crtc2_pitch |= save->crtc2_pitch << 16; + } else { + save->crtc2_pitch = (((pScrn->displayWidth * pScrn->bitsPerPixel) + + ((pScrn->bitsPerPixel * 8) -1)) / + (pScrn->bitsPerPixel * 8)); + save->crtc2_pitch |= save->crtc2_pitch << 16; + } - if (info->DisplayType == MT_DFP || info->CloneType == MT_DFP) { + if (info->DisplayType == MT_DFP || info->CloneType == MT_DFP + || info->MergeType == MT_DFP) { save->crtc2_gen_cntl = (RADEON_CRTC2_EN | (format << 8)); save->fp2_h_sync_strt_wid = save->crtc2_h_sync_strt_wid; save->fp2_v_sync_strt_wid = save->crtc2_v_sync_strt_wid; @@ -5292,7 +6266,7 @@ info->PanelOff = TRUE; } - if (info->PanelOff && info->Clone) { + if (info->PanelOff && (info->Clone || info->MergedFB)) { info->OverlayOnCRTC2 = TRUE; if (info->DisplayType == MT_LCD) { /* Turning off LVDS_ON seems to make panel white blooming. @@ -5493,6 +6467,23 @@ if (!RADEONInitCrtc2Registers(pScrn, save, mode, info)) return FALSE; RADEONInitPLL2Registers(save, &info->pll, dot_clock); + } else if (info->MergedFB) { + RADEONInitCommonRegisters(save, info); + if (!RADEONInitCrtcRegisters(pScrn, save, + ((RADEONMergedDisplayModePtr)mode->Private)->CRT1, info)) + return FALSE; + dot_clock = (((RADEONMergedDisplayModePtr)mode->Private)->CRT1)->Clock / 1000.0; + if (dot_clock) { + RADEONInitPLLRegisters(save, &info->pll, dot_clock); + } else { + save->ppll_ref_div = info->SavedReg.ppll_ref_div; + save->ppll_div_3 = info->SavedReg.ppll_div_3; + save->htotal_cntl = info->SavedReg.htotal_cntl; + } + RADEONInitCrtc2Registers(pScrn, save, + ((RADEONMergedDisplayModePtr)mode->Private)->CRT2, info); + dot_clock = (((RADEONMergedDisplayModePtr)mode->Private)->CRT2)->Clock / 1000.0; + RADEONInitPLL2Registers(save, &info->pll, dot_clock); } else { RADEONInitCommonRegisters(save, info); if (!RADEONInitCrtcRegisters(pScrn, save, mode, info)) @@ -5511,6 +6502,7 @@ dot_clock = info->CurCloneMode->Clock / 1000.0; RADEONInitPLL2Registers(save, &info->pll, dot_clock); } + /* Not used for now: */ /* if (!info->PaletteSavedOnVT) RADEONInitPalette(save); */ } @@ -5631,6 +6623,10 @@ info->IsSwitching = FALSE; } +#if 0 + if (info->MergedFB) + RADEONDoAdjustFrame(info->CRT2pScrn, info->CRT2pScrn->frameX0, info->CRT2pScrn->frameY0, TRUE); +#endif if (info->accelOn) { info->accel->Sync(pScrn); @@ -5691,13 +6687,20 @@ pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen); + if (clone || info->IsSecondary) { + pSAREAPriv->crtc2_base = Base; + } + if (pSAREAPriv->pfCurrentPage == 1) { Base += info->backOffset; } +/* moved this up to fix corruption on crtc2 with + pageflipping when changing modes if (clone || info->IsSecondary) { pSAREAPriv->crtc2_base = Base; } +*/ } #endif @@ -5715,7 +6718,9 @@ if (info->accelOn) info->accel->Sync(pScrn); - if (info->FBDev) { + if(info->MergedFB) { + RADEONAdjustFrameMerged(scrnIndex, x, y, flags); + } else if (info->FBDev) { fbdevHWAdjustFrame(scrnIndex, x, y, flags); } else { RADEONDoAdjustFrame(pScrn, x, y, FALSE); @@ -5833,6 +6838,40 @@ while (info->CloneModes) xf86DeleteMode(&info->CloneModes, info->CloneModes); + if(info->MergedFB) { + if(pScrn->modes) { + pScrn->currentMode = pScrn->modes; + do { + DisplayModePtr p = pScrn->currentMode->next; + if(pScrn->currentMode->Private) + xfree(pScrn->currentMode->Private); + xfree(pScrn->currentMode); + pScrn->currentMode = p; + } while(pScrn->currentMode != pScrn->modes); + } + pScrn->currentMode = info->CRT1CurrentMode; + pScrn->modes = info->CRT1Modes; + info->CRT1CurrentMode = NULL; + info->CRT1Modes = NULL; + + if(info->CRT2pScrn) { + if(info->CRT2pScrn->modes) { + while(info->CRT2pScrn->modes) + xf86DeleteMode(&info->CRT2pScrn->modes, info->CRT2pScrn->modes); + } + if(info->CRT2pScrn->monitor) { + if(info->CRT2pScrn->monitor->Modes) { + while(info->CRT2pScrn->monitor->Modes) + xf86DeleteMode(&info->CRT2pScrn->monitor->Modes, info->CRT2pScrn->monitor->Modes); + } + if(info->CRT2pScrn->monitor->DDC) xfree(info->CRT2pScrn->monitor->DDC); + xfree(info->CRT2pScrn->monitor); + } + xfree(info->CRT2pScrn); + info->CRT2pScrn = NULL; + } + } + pScrn->vtSema = FALSE; xf86ClearPrimInitDone(pScrn->entityList[0]); @@ -5885,7 +6924,7 @@ if (info->IsSecondary) OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~mask2); else { - if (info->Clone) + if (info->Clone || info->MergedFB) OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~mask2); OUTREGP(RADEON_CRTC_EXT_CNTL, 0, ~mask1); } @@ -5898,7 +6937,7 @@ RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS, ~mask2); else { - if (info->Clone) + if (info->Clone || info->MergedFB) OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS, ~mask2); @@ -5915,7 +6954,7 @@ RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS, ~mask2); else { - if (info->Clone) + if (info->Clone || info->MergedFB) OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS, ~mask2); @@ -5930,7 +6969,7 @@ if (info->IsSecondary) OUTREGP(RADEON_CRTC2_GEN_CNTL, mask2, ~mask2); else { - if (info->Clone) + if (info->Clone || info->MergedFB) OUTREGP(RADEON_CRTC2_GEN_CNTL, mask2, ~mask2); OUTREGP(RADEON_CRTC_EXT_CNTL, mask1, ~mask1); } --- ../ati.orig/radeon.h 2003-02-23 18:28:48.000000000 -0500 +++ radeon.h 2003-05-10 10:18:37.000000000 -0400 @@ -258,6 +258,15 @@ CHIP_FAMILY_R300 } RADEONChipFamily; +/* Relative merge position */ +typedef enum { + radeonLeftOf, + radeonRightOf, + radeonAbove, + radeonBelow, + radeonClone +} RADEONScrn2Rel; + typedef struct { EntityInfoPtr pEnt; pciVideoPtr PciInfo; @@ -530,8 +539,52 @@ #ifdef XFree86LOADER XF86ModReqInfo xaaReq; #endif + /* merged fb stuff */ + Bool MergedFB; + RADEONScrn2Rel CRT2Position; + char * CRT2HSync; + char * CRT2VRefresh; + char * MetaModes; + ScrnInfoPtr CRT2pScrn; + DisplayModePtr CRT1Modes; + DisplayModePtr CRT1CurrentMode; + int CRT1frameX0; + int CRT1frameY0; + int CRT1frameX1; + int CRT1frameY1; + /* Bool CheckForCRT2; + Bool IsCustomCRT2; */ + RADEONMonitorType MergeType; + RADEONDDCType MergeDDCType; + void (*PointerMoved)(int index, int x, int y); + } RADEONInfoRec, *RADEONInfoPtr; +#define SDMPTR(x) ((RADEONMergedDisplayModePtr)(x->currentMode->Private)) +#define CDMPTR ((RADEONMergedDisplayModePtr)(info->CurrentLayout.mode->Private)) + +#define BOUND(test,low,hi) { \ + if(test < low) test = low; \ + if(test > hi) test = hi; } + +#define REBOUND(low,hi,test) { \ + if(test < low) { \ + hi += test-low; \ + low = test; } \ + if(test > hi) { \ + low += test-hi; \ + hi = test; } } + +typedef struct _MergedDisplayModeRec { + DisplayModePtr CRT1; + DisplayModePtr CRT2; + RADEONScrn2Rel CRT2Position; +} RADEONMergedDisplayModeRec, *RADEONMergedDisplayModePtr; + +typedef struct _region { + int x0,x1,y0,y1; +} region; + #define RADEONWaitForFifo(pScrn, entries) \ do { \ if (info->fifo_slots < entries) \ --- ../ati.orig/radeon_video.c 2003-02-18 20:19:43.000000000 -0500 +++ radeon_video.c 2003-05-08 21:18:41.000000000 -0400 @@ -1067,6 +1067,16 @@ - info->CloneFrameY0 + pScrn->frameY0) << 16))); scaler_src = (1 << 14); + /* this needs some thought... */ + } else if (info->MergedFB && info->OverlayOnCRTC2) { + x_off = 0; + OUTREG(RADEON_OV1_Y_X_START, ((dstBox->x1 + x_off) | + ((dstBox->y1*y_mult) << 16))); + + OUTREG(RADEON_OV1_Y_X_END, ((dstBox->x2 + x_off) | + ((dstBox->y2*y_mult) << 16))); + scaler_src = (1 << 14); + } else { OUTREG(RADEON_OV0_Y_X_START, ((dstBox->x1 + x_off) | ((dstBox->y1*y_mult) << 16)));