--- old/r128_driver.c Fri Jan 4 16:22:26 2002 +++ new/r128_driver.c Sat Sep 7 15:46:04 2002 @@ -468,10 +468,17 @@ { R128InfoPtr info = R128PTR(pScrn); unsigned char *R128MMIO = info->MMIO; - if(info->isDFP) - OUTREGP(R128_FP_GEN_CNTL, R128_FP_BLANK_DIS, ~R128_FP_BLANK_DIS); + if(!info->IsSecondary) /* for DH */ + { + if(info->isDFP) + OUTREGP(R128_FP_GEN_CNTL, R128_FP_BLANK_DIS, ~R128_FP_BLANK_DIS); + else + OUTREGP(R128_CRTC_EXT_CNTL, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS); else - OUTREGP(R128_CRTC_EXT_CNTL, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS); + { + /* not sure what's needed here - no docs! this is a guess on my part */ + OUTREGP(R128_CRTC2_GEN_CNT, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS); + } } /* Unblank screen. */ @@ -480,10 +487,18 @@ R128InfoPtr info = R128PTR(pScrn); unsigned char *R128MMIO = info->MMIO; - if(info->isDFP) - OUTREGP(R128_FP_GEN_CNTL, 0, ~R128_FP_BLANK_DIS); + if(!info->IsSecondary) + { + if(info->isDFP) + OUTREGP(R128_FP_GEN_CNTL, 0, ~R128_FP_BLANK_DIS); + else + OUTREGP(R128_CRTC_EXT_CNTL, 0, ~R128_CRTC_DISPLAY_DIS); + } else - OUTREGP(R128_CRTC_EXT_CNTL, 0, ~R128_CRTC_DISPLAY_DIS); + { + /* not sure what's needed here - no docs! this is a guess on my part */ + OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC_DISPLAY_DIS); + } } /* Compute log base 2 of val. */ @@ -623,6 +638,17 @@ Disabling programming of FP registers.\n"); } +/* stuff might need to be added to r128.h to deal with this function... + +Not even sure what's needed, if anything +I guess secondary display would be crt in all cases + if(info->HasCRTC2) { } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s Display == Type %d\n", + (info->IsSecondary ? "Secondary" : "Primary"), + info->DisplayType); +*/ + return TRUE; } @@ -894,10 +920,13 @@ } else { info->isDFP = FALSE; info->isPro2 = FALSE; + info->HasCRTC2 = FALSE; switch (info->Chipset) { /* R128 Pro and Pro2 can have DFP, we will deal with it. No support for dual-head/xinerama yet. M3 can also have DFP, no support for now */ + + /* not sure which have support for dual head */ case PCI_CHIP_RAGE128TF: case PCI_CHIP_RAGE128TL: case PCI_CHIP_RAGE128TR: info->isPro2 = TRUE; @@ -909,7 +938,7 @@ case PCI_CHIP_RAGE128LE: case PCI_CHIP_RAGE128LF: case PCI_CHIP_RAGE128MF: - case PCI_CHIP_RAGE128ML: info->HasPanelRegs = TRUE; break; + case PCI_CHIP_RAGE128ML: info->HasPanelRegs = TRUE; info->HasCRTC2 = TRUE; break; case PCI_CHIP_RAGE128RE: case PCI_CHIP_RAGE128RF: case PCI_CHIP_RAGE128RG: @@ -967,6 +996,24 @@ R128MMIO = NULL; R128UnmapMMIO(pScrn); + if(info->IsSecondary) + { + /*FIXME: For now, split FB into two equal sections. This should + be able to be adjusted by user with a config option*/ + DevUnion* pPriv; + R128EntPtr pR128Ent; + R128InfoPtr info1; + pPriv = xf86GetEntityPrivate(pScrn->entityList[0], + gR128EntityIndex); + pR128Ent = pPriv->ptr; + pScrn->videoRam /= 2; + pR128Ent->pPrimaryScrn->videoRam = pScrn->videoRam; + info1 = R128PTR(pR128Ent->pPrimaryScrn); + info1->FbMapSize = pScrn->videoRam * 1024; + info->LinearAddr += pScrn->videoRam * 1024; + } + + /* RAM */ switch (info->MemCntl & 0x3) { case 0: /* SDR SGRAM 1:1 */ @@ -1777,10 +1824,43 @@ if (!R128GetRec(pScrn)) return FALSE; info = R128PTR(pScrn); - + info->IsSecondary = FALSE; info->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); if (info->pEnt->location.type != BUS_PCI) goto fail; + R128PreInt10Save(pScrn, &save1, &save2); /* does R128 have this function? */ + + if(xf86IsEntityShared(pScrn->entityList[0])) + { + if(xf86IsPrimInitDone(pScrn->entityList[0])) + { + DevUnion* pPriv; + R128EntPtr pR128Ent; + info->IsSecondary = TRUE; + pPriv = xf86GetEntityPrivate(pScrn->entityList[0], + gR128EntityIndex); + pR128Ent = pPriv->ptr; + if(pR128Ent->BypassSecondary) return FALSE; + pR128Ent->pSecondaryScrn = pScrn; + } + else + { + DevUnion* pPriv; + R128EntPtr pR128Ent; + xf86SetPrimInitDone(pScrn->entityList[0]); + pPriv = xf86GetEntityPrivate(pScrn->entityList[0], + gRADEONEntityIndex); + pR128Ent = pPriv->ptr; + pR128Ent->pPrimaryScrn = pScrn; + pR128Ent->IsDRIEnabled = FALSE; + pR128Ent->BypassSecondary = FALSE; + pR128Ent->HasSecondary = FALSE; + pR128Ent->RestorePrimary = FALSE; + pR128Ent->IsSecondaryRestored = FALSE; + } + } + + if (flags & PROBE_DETECT) { R128ProbeDDC(pScrn, info->pEnt->index); return TRUE; @@ -1913,9 +1993,16 @@ R128InfoPtr info = R128PTR(pScrn); unsigned char *R128MMIO = info->MMIO; int i; - int idx; + int idx, j; unsigned char r, g, b; + /* If the second monitor is connected, we also + need to deal with the secondary palette*/ + if (info->IsSecondary) j = 1; + else j = 0; + + PAL_SELECT(j); /* PAL_SELECT() probably needs to be updated to work here */ + /* Select palette 0 (main CRTC) if using FP-enabled chip */ if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0); @@ -2046,9 +2133,38 @@ (pScrn->displayWidth * pScrn->virtualY * info->CurrentLayout.pixel_bytes * 3 + 1023) / 1024); info->directRenderingEnabled = FALSE; - } else { - info->directRenderingEnabled = R128DRIScreenInit(pScreen); + } + + else { + if(info->IsSecondary) + info->directRenderingEnabled = FALSE; + else + { + /* Xinerama has sync problem with DRI, disable it for now */ + if(xf86IsEntityShared(pScrn->entityList[0])) + { + info->directRenderingEnabled = FALSE; + xf86DrvMsg(scrnIndex, X_WARNING, + "Direct Rendering Disabled -- " + "Dual-head configuration is not working with DRI " + "at present.\nPlease use only one Device/Screen " + "section in your XFConfig file.\n"); + } + else + info->directRenderingEnabled = + R128DRIScreenInit(pScreen); + if(xf86IsEntityShared(pScrn->entityList[0])) + { + DevUnion* pPriv; + R128EntPtr pR128Ent; + pPriv = xf86GetEntityPrivate(pScrn->entityList[0], + gR128EntityIndex); + pR128Ent = pPriv->ptr; + pR128Ent->IsDRIEnabled = info->directRenderingEnabled; + } + } } + } #endif @@ -2482,6 +2598,35 @@ OUTREG(R128_CRTC_PITCH, restore->crtc_pitch); } +/* Write CRTC2 registers. */ +static void R128RestoreCrtc2Registers(ScrnInfoPtr pScrn, + R128SavePtr restore) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + +/* this function probably needs lots of work...someone with docs...I just guessed */ + +/* OUTREG(RADEON_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl);*/ + OUTREGP(R128_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl, + RADEON_CRTC2_VSYNC_DIS | + RADEON_CRTC2_HSYNC_DIS | + RADEON_CRTC2_DISP_DIS); + + OUTREG(R128_DAC_CRT_SEL_CRTC2, R128_DAC_CNTL, restore->dac2_cntl); +/* OUTREG(RADEON_DISP_OUTPUT_CNTL, restore->disp_output_cntl); */ + + OUTREG(R128_CRTC2_H_TOTAL_DISP, restore->crtc2_h_total_disp); + OUTREG(R128_CRTC2_H_SYNC_STRT_WID, restore->crtc2_h_sync_strt_wid); + OUTREG(R128_CRTC2_V_TOTAL_DISP, restore->crtc2_v_total_disp); + OUTREG(R128_CRTC2_V_SYNC_STRT_WID, restore->crtc2_v_sync_strt_wid); + OUTREG(R128_CRTC2_OFFSET, restore->crtc2_offset); + OUTREG(R128_CRTC2_OFFSET_CNTL, restore->crtc2_offset_cntl); + OUTREG(R128_CRTC2_PITCH, restore->crtc2_pitch); + +} + + /* Write flat panel registers */ static void R128RestoreFPRegisters(ScrnInfoPtr pScrn, R128SavePtr restore) { @@ -2579,6 +2724,53 @@ (restore->ppll_div_3 & R128_PPLL_POST3_DIV_MASK) >> 16)); } +/* Write PLL2 registers. This function is also broken I just copied it from the PLL function*/ +static void R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + OUTREGP(R128_CLOCK_CNTL_INDEX, R128_PLL_DIV_SEL, 0xffff); + + OUTPLLP(pScrn, + R128_PPLL_CNTL, + R128_PPLL_RESET + | R128_PPLL_ATOMIC_UPDATE_EN + | R128_PPLL_VGA_ATOMIC_UPDATE_EN, + 0xffff); + + R128PLLWaitForReadUpdateComplete(pScrn); + OUTPLLP(pScrn, R128_PPLL_REF_DIV, + restore->p2pll_ref_div, ~R128_PPLL_REF_DIV_MASK); + R128PLLWriteUpdate(pScrn); + + R128PLLWaitForReadUpdateComplete(pScrn); + OUTPLLP(pScrn, R128_PPLL_DIV_0, + restore->p2pll_div_0, ~R128_PPLL_FB3_DIV_MASK); + R128PLLWriteUpdate(pScrn); + OUTPLLP(pScrn, R128_PPLL_DIV_0, + restore->p2pll_div_0, ~R128_PPLL_POST3_DIV_MASK); + R128PLLWriteUpdate(pScrn); + + R128PLLWaitForReadUpdateComplete(pScrn); + OUTPLL(R128_HTOTAL_CNTL, restore->htotal_cntl2); + R128PLLWriteUpdate(pScrn); + + OUTPLLP(pScrn, R128_PPLL_CNTL, 0, ~R128_PPLL_RESET); + + R128TRACE(("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + restore->p2pll_ref_div, + restore->ppll_div_0, + restore->htotal_cntl2, + INPLL(pScrn, R128_PPLL_CNTL))); + R128TRACE(("Wrote: rd=%d, fd=%d, pd=%d\n", + restore->p2pll_ref_div & R128_PPLL_REF_DIV_MASK, + restore->ppll_div_0 & R128_PPLL_FB3_DIV_MASK, + (restore->ppll_div_0 & R128_PPLL_POST3_DIV_MASK) >> 16)); +} + + + /* Write DDA registers. */ static void R128RestoreDDARegisters(ScrnInfoPtr pScrn, R128SavePtr restore) { @@ -2606,21 +2798,83 @@ } /* Write out state to define a new video mode. */ +/* this needs work too I suspect... */ static void R128RestoreMode(ScrnInfoPtr pScrn, R128SavePtr restore) { - R128InfoPtr info = R128PTR(pScrn); + if(!info->HasCRTC2) + { + R128InfoPtr info = R128PTR(pScrn); + + R128TRACE(("R128RestoreMode(%p)\n", restore)); + R128RestoreCommonRegisters(pScrn, restore); + R128RestoreCrtcRegisters(pScrn, restore); + if (!(info->HasPanelRegs) || info->BIOSDisplay == R128_BIOS_DISPLAY_CRT){ + R128RestorePLLRegisters(pScrn, restore); + } + R128RestoreDDARegisters(pScrn, restore); + if (info->HasPanelRegs || info->isDFP) + R128RestoreFPRegisters(pScrn, restore); + + R128RestorePalette(pScrn, restore); + } + + /***** + When changing mode with Dual-head card (VE/M6), care must + be taken for the special order in setting registers. CRTC2 has + to be set before changing CRTC_EXT register. + In the dual-head setup, X server calls this routine twice with + primary and secondary pScrn pointers respectively. The calls + can come with different order. Regardless the order of X server issuing + the calls, we have to ensure we set registers in the right order!!! + Otherwise we may get a blank screen. + *****/ + if(info->IsSecondary) + { + R128RestoreCrtc2Registers(pScrn, restore); + R128RestorePLL2Registers(pScrn, restore); + + if(!info->SwitchingMode) + pR128Ent->IsSecondaryRestored = TRUE; + + if(pR128Ent->RestorePrimary) + { + R128InfoPtr info0 = R128PTR(pR128Ent->pPrimaryScrn); + pR128Ent->RestorePrimary = FALSE; - R128TRACE(("R128RestoreMode(%p)\n", restore)); - R128RestoreCommonRegisters(pScrn, restore); - R128RestoreCrtcRegisters(pScrn, restore); - if (!(info->HasPanelRegs) || info->BIOSDisplay == R128_BIOS_DISPLAY_CRT){ - R128RestorePLLRegisters(pScrn, restore); + R128RestoreCrtcRegisters(pScrn, &restore0); + if((info0->HasPanelRegs) + { + R128RestoreFPRegisters(pScrn, &restore0); + } + + R128RestorePLLRegisters(pScrn, &restore0); + pR128Ent->IsSecondaryRestored = FALSE; + + } } - R128RestoreDDARegisters(pScrn, restore); - if (info->HasPanelRegs || info->isDFP) - R128RestoreFPRegisters(pScrn, restore); + else + { + R128RestoreCommonRegisters(pScrn, restore); + R128RestoreDDARegisters(pScrn, restore); + if(!pR128Ent->HasSecondary || pR128Ent->IsSecondaryRestored + || info->SwitchingMode) + { + pR128Ent->IsSecondaryRestored = FALSE; + R128RestoreCrtcRegisters(pScrn, restore); + if((info->HasPanelRegs) + { + R128RestoreFPRegisters(pScrn, restore); + } + R128RestorePLLRegisters(pScrn, restore); + } + else + { + memcpy(&restore0, restore, sizeof(restore0)); + pR128Ent->RestorePrimary = TRUE; + } + } + - R128RestorePalette(pScrn, restore); } /* Read common registers. */ @@ -2663,6 +2917,26 @@ save->crtc_pitch = INREG(R128_CRTC_PITCH); } +/* Read CRTC2 registers. */ +/* may be wrong...no docs. */ +static void R128SaveCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save) +{ + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + save->crtc2_gen_cntl = INREG(R128_CRTC2_GEN_CNTL); + save->crtc_ext_cntl = INREG(R128_CRTC_EXT_CNTL); + save->dac_cntl = INREG(R128_DAC_CNTL); + save->crtc2_h_total_disp = INREG(R128_CRTC_H_TOTAL_DISP); + save->crtc2_h_sync_strt_wid = INREG(R128_CRTC_H_SYNC_STRT_WID); + save->crtc2_v_total_disp = INREG(R128_CRTC_V_TOTAL_DISP); + save->crtc2_v_sync_strt_wid = INREG(R128_CRTC_V_SYNC_STRT_WID); + save->crtc2_offset = INREG(R128_CRTC_OFFSET); + save->crtc2_offset_cntl = INREG(R128_CRTC_OFFSET_CNTL); + save->crtc2_pitch = INREG(R128_CRTC_PITCH); +} + + /* Read flat panel registers */ static void R128SaveFPRegisters(ScrnInfoPtr pScrn, R128SavePtr save) { @@ -2700,6 +2974,25 @@ (save->ppll_div_3 & R128_PPLL_POST3_DIV_MASK) >> 16)); } +/* Read PLL2 registers. */ +/* needs work too */ +static void R128SavePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save) +{ + save->p2pll_ref_div = INPLL(pScrn, R128_PPLL_REF_DIV); + save->ppll_div_0 = INPLL(pScrn, R128_PPLL_DIV_0); + save->htotal_cntl2 = INPLL(pScrn, R128_HTOTAL_CNTL); + + R128TRACE(("Read: 0x%08x 0x%08x 0x%08x\n", + save->ppll_ref_div, + save->ppll_div_0, + save->htotal_cntl)); + R128TRACE(("Read: rd=%d, fd=%d, pd=%d\n", + save->ppll_ref_div & R128_PPLL_REF_DIV_MASK, + save->ppll_div_0 & R128_PPLL_FB3_DIV_MASK, + (save->ppll_div_0 & R128_PPLL_POST3_DIV_MASK) >> 16)); +} + + /* Read DDA registers. */ static void R128SaveDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save) { @@ -2730,15 +3023,23 @@ { R128TRACE(("R128SaveMode(%p)\n", save)); - R128SaveCommonRegisters(pScrn, save); - R128SaveCrtcRegisters(pScrn, save); - if (R128PTR(pScrn)->HasPanelRegs || R128PTR(pScrn)->isDFP) - R128SaveFPRegisters(pScrn, save); - R128SavePLLRegisters(pScrn, save); - R128SaveDDARegisters(pScrn, save); - R128SavePalette(pScrn, save); - + if(info->IsSecondary) + { + R128SaveCrtc2Registers(pScrn, save); + R128SavePLL2Registers(pScrn, save); + } + else + { + R128SaveCommonRegisters(pScrn, save); + R128SaveCrtcRegisters(pScrn, save); + if (R128PTR(pScrn)->HasPanelRegs || R128PTR(pScrn)->isDFP) + R128SaveFPRegisters(pScrn, save); + R128SavePLLRegisters(pScrn, save); + R128SaveDDARegisters(pScrn, save); + R128SavePalette(pScrn, save); + } R128TRACE(("R128SaveMode returns %p\n", save)); + } /* Save everything needed to restore the original VC state. */ @@ -2754,9 +3055,12 @@ fbdevHWSave(pScrn); return; } + if(!info->IsSecondary) + { vgaHWUnlock(hwp); vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL); /* save mode, fonts, cmap */ vgaHWLock(hwp); + } R128SaveMode(pScrn, save); @@ -2789,9 +3093,27 @@ OUTREG(R128_DP_DATATYPE, restore->dp_datatype); R128RestoreMode(pScrn, restore); + + if(!info->IsSecondary) + { vgaHWUnlock(hwp); - vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS ); - vgaHWLock(hwp); + } + else + { + DevUnion* pPriv; + R128EntPtr pR128Ent; + pPriv = xf86GetEntityPrivate(pScrn->entityList[0], + gR128EntityIndex); + pR128Ent = pPriv->ptr; + { + ScrnInfoPtr pScrn0 = pR128Ent->pPrimaryScrn; + vgaHWPtr hwp0 = VGAHWPTR(pScrn0); + vgaHWUnlock(hwp0); + vgaHWRestore(pScrn0, &hwp0->SavedReg, + VGA_SR_MODE | VGA_SR_FONTS ); + vgaHWLock(hwp0); + } + } R128WaitForVerticalSync(pScrn); R128Unblank(pScrn); @@ -2952,6 +3274,141 @@ return TRUE; } + +/* Define CRTC2 registers for requested video mode. */ +/* needs work */ +static Bool R128InitCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save, + DisplayModePtr mode, R128InfoPtr info) +{ + int format; + int hsync_start; + int hsync_wid; + int hsync_fudge; + int vsync_wid; + int bytpp; + int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; + int hsync_fudge_fp[] = { 0x12, 0x11, 0x09, 0x09, 0x05, 0x05 }; + int hsync_fudge_fp_crt[] = { 0x12, 0x10, 0x08, 0x08, 0x04, 0x04 }; + + switch (info->CurrentLayout.pixel_code) { + case 4: format = 1; bytpp = 0; break; + case 8: format = 2; bytpp = 1; break; + case 15: format = 3; bytpp = 2; break; /* 555 */ + case 16: format = 4; bytpp = 2; break; /* 565 */ + case 24: format = 5; bytpp = 3; break; /* RGB */ + case 32: format = 6; bytpp = 4; break; /* xRGB */ + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unsupported pixel depth (%d)\n", + info->CurrentLayout.bitsPerPixel); + return FALSE; + } + R128TRACE(("Format = %d (%d bytes per pixel)\n", format, bytpp)); + + switch (info->BIOSDisplay) { + case R128_BIOS_DISPLAY_FP: + hsync_fudge = hsync_fudge_fp[format-1]; + break; + case R128_BIOS_DISPLAY_FP_CRT: + hsync_fudge = hsync_fudge_fp_crt[format-1]; + break; + case R128_BIOS_DISPLAY_CRT: + default: + hsync_fudge = hsync_fudge_default[format-1]; + break; + } + + save->crtc2_gen_cntl = (R128_CRTC_EXT_DISP_EN + | R128_CRTC_EN + | (format << 8) + | ((mode->Flags & V_DBLSCAN) + ? R128_CRTC_DBL_SCAN_EN + : 0) + | ((mode->Flags & V_INTERLACE) + ? R128_CRTC_INTERLACE_EN + : 0) + | ((mode->Flags & V_CSYNC) + ? R128_CRTC_CSYNC_EN + : 0)); + + save->crtc_ext_cntl = R128_VGA_ATI_LINEAR | R128_XCRT_CNT_EN; + save->dac_cntl = (R128_DAC_MASK_ALL + | R128_DAC_VGA_ADR_EN + | (info->dac6bits ? 0 : R128_DAC_8BIT_EN)); + + + if(info->isDFP && !info->isPro2) + { + if(info->PanelXRes < mode->CrtcHDisplay) + mode->HDisplay = mode->CrtcHDisplay = info->PanelXRes; + if(info->PanelYRes < mode->CrtcVDisplay) + mode->VDisplay = mode->CrtcVDisplay = info->PanelYRes; + mode->CrtcHTotal = mode->CrtcHDisplay + info->HBlank; + mode->CrtcHSyncStart = mode->CrtcHDisplay + info->HOverPlus; + mode->CrtcHSyncEnd = mode->CrtcHSyncStart + info->HSyncWidth; + mode->CrtcVTotal = mode->CrtcVDisplay + info->VBlank; + mode->CrtcVSyncStart = mode->CrtcVDisplay + info->VOverPlus; + mode->CrtcVSyncEnd = mode->CrtcVSyncStart + info->VSyncWidth; + } + + save->crtc2_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0xffff) + | (((mode->CrtcHDisplay / 8) - 1) << 16)); + + hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8; + if (!hsync_wid) hsync_wid = 1; + if (hsync_wid > 0x3f) hsync_wid = 0x3f; + + hsync_start = mode->CrtcHSyncStart - 8 + hsync_fudge; + + save->crtc2_h_sync_strt_wid = ((hsync_start & 0xfff) + | (hsync_wid << 16) + | ((mode->Flags & V_NHSYNC) + ? R128_CRTC_H_SYNC_POL + : 0)); + +#if 1 + /* This works for double scan mode. */ + save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) + | ((mode->CrtcVDisplay - 1) << 16)); +#else + /* This is what cce/nbmode.c example code + does -- is this correct? */ + save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) + | ((mode->CrtcVDisplay + * ((mode->Flags & V_DBLSCAN) ? 2 : 1) - 1) + << 16)); +#endif + + vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; + if (!vsync_wid) vsync_wid = 1; + if (vsync_wid > 0x1f) vsync_wid = 0x1f; + + save->crtc2_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff) + | (vsync_wid << 16) + | ((mode->Flags & V_NVSYNC) + ? R128_CRTC_V_SYNC_POL + : 0)); + save->crtc2_offset = 0; + save->crtc2_offset_cntl = 0; + save->crtc2_pitch = info->CurrentLayout.displayWidth / 8; + + R128TRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n", + save->crtc_pitch, pScrn->virtualX, info->CurrentLayout.displayWidth)); + +#if X_BYTE_ORDER == X_BIG_ENDIAN + /* Change the endianness of the aperture */ + switch (info->CurrentLayout.pixel_code) { + case 15: + case 16: save->config_cntl |= APER_0_BIG_ENDIAN_16BPP_SWAP; break; + case 32: save->config_cntl |= APER_0_BIG_ENDIAN_32BPP_SWAP; break; + default: break; + } +#endif + + return TRUE; +} + + /* Define CRTC registers for requested video mode. */ static void R128InitFPRegisters(R128SavePtr orig, R128SavePtr save, DisplayModePtr mode, R128InfoPtr info) @@ -3023,14 +3480,16 @@ want to use the dual CRTC capabilities of the R128 to allow both the flat panel and external CRT to either simultaneously display the same image or display two different images. */ + +/* something needs to be done here, I suspect, so that dual head is enabled properly */ if(!info->isDFP){ if (info->BIOSDisplay == R128_BIOS_DISPLAY_FP_CRT) { save->crtc_ext_cntl |= R128_CRTC_CRT_ON; } else { - save->crtc_ext_cntl &= ~R128_CRTC_CRT_ON; + save->crtc_ext_cntl &= R128_CRTC_CRT_ON; save->dac_cntl |= R128_DAC_CRT_SEL_CRTC2; - save->crtc2_gen_cntl = 0; + save->crtc2_gen_cntl = 1; } } @@ -3112,6 +3571,59 @@ } + +/* Define PLL2 registers for requested video mode. */ +static void R128InitPLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save, + R128PLLPtr pll, double dot_clock) +{ + unsigned long freq = dot_clock * 100; + struct { + int divider; + int bitvalue; + } *post_div, + post_divs[] = { + /* From RAGE 128 VR/RAGE 128 GL Register + Reference Manual (Technical Reference + Manual P/N RRG-G04100-C Rev. 0.04), page + 3-17 (PLL_DIV_[3:0]). */ + { 1, 0 }, /* VCLK_SRC */ + { 2, 1 }, /* VCLK_SRC/2 */ + { 4, 2 }, /* VCLK_SRC/4 */ + { 8, 3 }, /* VCLK_SRC/8 */ + + { 3, 4 }, /* VCLK_SRC/3 */ + /* bitvalue = 5 is reserved */ + { 6, 6 }, /* VCLK_SRC/6 */ + { 12, 7 }, /* VCLK_SRC/12 */ + { 0, 0 } + }; + + if (freq > pll->max_pll_freq) freq = pll->max_pll_freq; + if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12; + + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + save->pll_output_freq_2 = post_div->divider * freq; + if (save->pll_output_freq_2 >= pll->min_pll_freq + && save->pll_output_freq_2 <= pll->max_pll_freq) break; + } + + save->dot_clock_freq = freq; + save->feedback_div = R128Div(pll->reference_div * save->pll_output_freq, + pll->reference_freq); + save->post_div = post_div->divider; + + R128TRACE(("dc=%d, of=%d, fd=%d, pd=%d\n", + save->dot_clock_freq_2, + save->pll_output_freq_2, + save->feedback_div_2, + save->post_div_2)); + + save->p2pll_ref_div = pll->reference_div; + save->ppll_div_0 = (save->feedback_div | (post_div->bitvalue << 16)); + save->htotal_cntl2 = 0; + +} + /* Define DDA registers for requested video mode. */ static Bool R128InitDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save, R128PLLPtr pll, R128InfoPtr info, @@ -3246,6 +3758,15 @@ info->Flags = mode->Flags; + if(info->IsSecondary) + { + if (!R128InitCrtc2Registers(pScrn, save, + pScrn->currentMode,info)) + return FALSE; + R128InitPLL2Registers(save, &info->pll, dot_clock); + } + else + { R128InitCommonRegisters(save, info); if (!R128InitCrtcRegisters(pScrn, save, mode, info)) return FALSE; if (info->HasPanelRegs || info->isDFP) @@ -3262,6 +3783,7 @@ save->dda_config = info->SavedReg.dda_config; save->dda_on_off = info->SavedReg.dda_on_off; } + } R128TRACE(("R128Init returns %p\n", save)); return TRUE; @@ -3304,7 +3826,18 @@ Bool R128SwitchMode(int scrnIndex, DisplayModePtr mode, int flags) { + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + R128InfoPtr info = R128PTR(pScrn); + + /* when switch mode in dual-head setup, this function will be called + separately for each screen (depending on which screen the cursor is + in when user press ctrl-alt-+). Since this function is always + called when screen already in extensive mode, the sequence of + setting CRTC2 and CRT_EXT regesters doesn't matter any more, + So we set the flag for RADEONRestoreMode here. */ + info->SwitchingMode = TRUE; return R128ModeInit(xf86Screens[scrnIndex], mode); + info->SwitchingMode = FALSE; } /* Used to disallow modes that are not supported by the hardware. */ @@ -3394,7 +3927,12 @@ if (info->CurrentLayout.pixel_code == 24) Base += 8 * (Base % 3); /* Must be multiple of 8 and 3 */ - + if(info->IsSecondary) + { + Base += pScrn->fbOffset; + OUTREG(R128_CRTC2_OFFSET, Base); + } + else OUTREG(R128_CRTC_OFFSET, Base); }