[PATCH] dualhead support for r128
Alex Deucher <[email protected]>
| Newsgroups | gmane.linux.redhat.xfree86 |
|---|---|
| Message-ID | <[email protected]> |
well, I finally got around to finishing my patch. here it is. I need some people to test it because I don't have a laptop with a r128 chip in it. Also, someone with r128 mobility docs might want to look over the code since I coded it from the radeon driver and since I don't have r128 docs, I have to assume the they share the sames regs for dualhead. I would imagine they do though since most of the rest of the stuff is very similar. The patch is against xfree86 4.3.0. raw files are available here: http://www.botchco.com/alex/r128/4.3/ati/ diff and binary for redhat 9: http://www.botchco.com/alex/r128/final/ Thanks, Alex __________________________________________________ Do you Yahoo!? The New Yahoo! Search - Faster. Easier. Bingo http://search.yahoo.com
r128_dualhead.diff
(application/octet-stream, 46.7 KB)
--- ../ati.orig/r128_accel.c 2002-11-14 22:01:35.000000000 -0500
+++ r128_accel.c 2003-04-17 20:03:14.000000000 -0400
@@ -83,6 +83,7 @@
#include "r128.h"
#include "r128_reg.h"
#include "r128_sarea.h"
+#include "r128_probe.h"
#ifdef XF86DRI
#include "r128_sarea.h"
#define _XF86DRI_SERVER_
@@ -117,6 +118,8 @@
{ R128_ROP3_ONE, R128_ROP3_ONE } /* GXset */
};
+extern int gR128EntityIndex;
+
/* Flush all dirty data in the Pixel Cache to memory. */
void R128EngineFlush(ScrnInfoPtr pScrn)
{
@@ -1641,6 +1644,25 @@
&indirect, sizeof(drmR128Indirect));
}
+/* This callback is required for multihead cards using XAA */
+static
+void R128RestoreCCEAccelState(ScrnInfoPtr pScrn)
+{
+ R128InfoPtr info = R128PTR(pScrn);
+/* unsigned char *R128MMIO = info->MMIO; needed for OUTREG below */
+ /*xf86DrvMsg(pScrn->scrnIndex, X_INFO, "===>RestoreCP\n");*/
+
+ R128WaitForFifo(pScrn, 1);
+/* is this needed on r128
+ OUTREG( R128_DEFAULT_OFFSET, info->frontPitchOffset);
+*/
+ R128WaitForIdle(pScrn);
+
+ /* FIXME: May need to restore other things,
+ like BKGD_CLK FG_CLK...*/
+
+}
+
static void R128CCEAccelInit(ScrnInfoPtr pScrn, XAAInfoRecPtr a)
{
R128InfoPtr info = R128PTR(pScrn);
@@ -1701,9 +1723,47 @@
| HARDWARE_PATTERN_PROGRAMMED_ORIGIN
| HARDWARE_PATTERN_SCREEN_ORIGIN
| BIT_ORDER_IN_BYTE_LSBFIRST);
+
+ if(!info->IsSecondary && xf86IsEntityShared(pScrn->entityList[0]))
+ a->RestoreAccelState = R128RestoreCCEAccelState;
+
}
#endif
+/* This callback is required for multihead cards using XAA */
+static
+void R128RestoreAccelState(ScrnInfoPtr pScrn)
+{
+ R128InfoPtr info = R128PTR(pScrn);
+ unsigned char *R128MMIO = info->MMIO;
+ CARD32 pitch64;
+ R128EntPtr pR128Ent;
+ DevUnion* pPriv;
+
+ pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
+ gR128EntityIndex);
+ pR128Ent = pPriv->ptr;
+ if(pR128Ent->IsDRIEnabled)
+ {
+ /*not working yet*/
+ /*
+ RADEONInfoPtr info0 = RADEONPTR(pRADEONEnt->pPrimaryScrn);
+ RADEONCP_TO_MMIO(pRADEONEnt->pPrimaryScrn, info0);
+ */
+ }
+ pitch64 = ((pScrn->displayWidth * (pScrn->bitsPerPixel / 8) + 0x3f)) >> 6;
+
+ OUTREG(R128_DEFAULT_OFFSET, (pScrn->fbOffset>>10) |
+ (pitch64 << 22));
+
+ /* FIXME: May need to restore other things,
+ like BKGD_CLK FG_CLK...*/
+
+ R128WaitForIdle(pScrn);
+
+}
+
+
static void R128MMIOAccelInit(ScrnInfoPtr pScrn, XAAInfoRecPtr a)
{
R128InfoPtr info = R128PTR(pScrn);
@@ -1768,6 +1828,22 @@
a->DashedLineFlags = (LINE_PATTERN_LSBFIRST_LSBJUSTIFIED
| LINE_PATTERN_POWER_OF_2_ONLY);
+
+ if(xf86IsEntityShared(pScrn->entityList[0]))
+ {
+ DevUnion* pPriv;
+ R128EntPtr pR128Ent;
+ pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
+ gR128EntityIndex);
+ pR128Ent = pPriv->ptr;
+
+ /*if there are more than one devices sharing this entity, we
+ have to assign this call back, otherwise the XAA will be
+ disabled */
+ if(pR128Ent->HasSecondary || pR128Ent->BypassSecondary)
+ a->RestoreAccelState = R128RestoreAccelState;
+ }
+
/* ImageWrite */
a->NumScanlineImageWriteBuffers = 1;
a->ScanlineImageWriteBuffers = info->scratch_buffer;
--- ../ati.orig/r128_cursor.c 2003-02-13 15:28:40.000000000 -0500
+++ r128_cursor.c 2003-04-17 19:31:11.000000000 -0400
@@ -72,8 +72,16 @@
R128InfoPtr info = R128PTR(pScrn);
unsigned char *R128MMIO = info->MMIO;
- OUTREG(R128_CUR_CLR0, bg);
- OUTREG(R128_CUR_CLR1, fg);
+ if(info->IsSecondary)
+ {
+ OUTREG(R128_CUR2_CLR0, bg);
+ OUTREG(R128_CUR2_CLR1, fg);
+ }
+ else
+ {
+ OUTREG(R128_CUR_CLR0, bg);
+ OUTREG(R128_CUR_CLR1, fg);
+ }
}
/* Set cursor position to (x,y) with offset into cursor bitmap at
@@ -94,11 +102,26 @@
if (xorigin >= cursor->MaxWidth) xorigin = cursor->MaxWidth - 1;
if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1;
- OUTREG(R128_CUR_HORZ_VERT_OFF, R128_CUR_LOCK | (xorigin << 16) | yorigin);
- OUTREG(R128_CUR_HORZ_VERT_POSN, (R128_CUR_LOCK
+ if(!info->IsSecondary)
+ {
+ OUTREG(R128_CUR_HORZ_VERT_OFF, R128_CUR_LOCK | (xorigin << 16) | yorigin);
+ OUTREG(R128_CUR_HORZ_VERT_POSN, (R128_CUR_LOCK
| ((xorigin ? 0 : x) << 16)
| (yorigin ? 0 : y)));
- OUTREG(R128_CUR_OFFSET, info->cursor_start + yorigin * 16);
+ OUTREG(R128_CUR_OFFSET, info->cursor_start + yorigin * 16);
+ }
+ else
+ {
+ OUTREG(R128_CUR2_HORZ_VERT_OFF, (R128_CUR2_LOCK
+ | (xorigin << 16)
+ | yorigin));
+ OUTREG(R128_CUR2_HORZ_VERT_POSN, (R128_CUR2_LOCK
+ | ((xorigin ? 0 : x) << 16)
+ | (yorigin ? 0 : y)));
+ OUTREG(R128_CUR2_OFFSET,
+ info->cursor_start + pScrn->fbOffset + yorigin * 16);
+ }
+
}
/* Copy cursor image from `image' to video memory. R128SetCursorPosition
@@ -112,8 +135,16 @@
int y;
CARD32 save;
- save = INREG(R128_CRTC_GEN_CNTL);
- OUTREG(R128_CRTC_GEN_CNTL, save & (CARD32)~R128_CRTC_CUR_EN);
+ if(!info->IsSecondary)
+ {
+ save = INREG(R128_CRTC_GEN_CNTL);
+ OUTREG(R128_CRTC_GEN_CNTL, save & (CARD32)~R128_CRTC_CUR_EN);
+ }
+ else
+ {
+ save = INREG(R128_CRTC2_GEN_CNTL);
+ OUTREG(R128_CRTC2_GEN_CNTL, save & (CARD32)~R128_CRTC2_CUR_EN);
+ }
#if X_BYTE_ORDER == X_BIG_ENDIAN
switch(info->CurrentLayout.pixel_bytes) {
@@ -168,8 +199,10 @@
*d++ = 0x00000000;
}
-
- OUTREG(R128_CRTC_GEN_CNTL, save);
+ if(!info->IsSecondary)
+ OUTREG(R128_CRTC_GEN_CNTL, save);
+ else
+ OUTREG(R128_CRTC2_GEN_CNTL, save);
}
/* Hide hardware cursor. */
@@ -178,7 +211,10 @@
R128InfoPtr info = R128PTR(pScrn);
unsigned char *R128MMIO = info->MMIO;
- OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_CUR_EN);
+ if(info->IsSecondary)
+ OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_CUR_EN);
+ else
+ OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_CUR_EN);
}
/* Show hardware cursor. */
@@ -187,7 +223,15 @@
R128InfoPtr info = R128PTR(pScrn);
unsigned char *R128MMIO = info->MMIO;
- OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_CUR_EN, ~R128_CRTC_CUR_EN);
+ if(info->IsSecondary)
+ {
+ OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_CUR_EN,
+ ~R128_CRTC2_CUR_EN);
+ }
+ else
+ {
+ OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_CUR_EN, ~R128_CRTC_CUR_EN);
+ }
}
/* Determine if hardware cursor is in use. */
--- ../ati.orig/r128_driver.c 2003-02-18 20:19:41.000000000 -0500
+++ r128_driver.c 2003-04-17 20:19:45.000000000 -0400
@@ -358,6 +358,8 @@
NULL);
}
+extern int gR128EntityIndex;
+
/* Allocate our private R128InfoRec. */
static Bool R128GetRec(ScrnInfoPtr pScrn)
{
@@ -500,10 +502,24 @@
{
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)
+ {
+ 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);
+ {
+ OUTREGP(R128_CRTC2_GEN_CNTL,
+ R128_CRTC2_DISP_DIS |
+ R128_CRTC2_VSYNC_DIS |
+ R128_CRTC2_HSYNC_DIS,
+ ~(R128_CRTC2_DISP_DIS |
+ R128_CRTC2_VSYNC_DIS |
+ R128_CRTC2_HSYNC_DIS));
+ }
}
/* Unblank screen. */
@@ -511,11 +527,21 @@
{
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);
+ {
+ OUTREGP(R128_CRTC2_GEN_CNTL, 0,
+ ~(R128_CRTC2_DISP_DIS |
+ R128_CRTC2_VSYNC_DIS |
+ R128_CRTC2_HSYNC_DIS));
+ }
+
}
/* Compute log base 2 of val. */
@@ -926,6 +952,7 @@
} 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.
@@ -975,7 +1002,11 @@
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;
+ /* which chips support dualhead? */
+ info->HasCRTC2 = TRUE;
+ break;
case PCI_CHIP_RAGE128RE:
case PCI_CHIP_RAGE128RF:
case PCI_CHIP_RAGE128RG:
@@ -1008,6 +1039,23 @@
else
pScrn->videoRam = INREG(R128_CONFIG_MEMSIZE) / 1024;
+ 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;
+ }
+
info->MemCntl = INREG(R128_MEM_CNTL);
info->BusCntl = INREG(R128_BUS_CNTL);
@@ -1877,6 +1925,36 @@
info->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
if (info->pEnt->location.type != BUS_PCI) goto fail;
+ 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],
+ gR128EntityIndex);
+ 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;
@@ -2009,12 +2087,21 @@
{
R128InfoPtr info = R128PTR(pScrn);
unsigned char *R128MMIO = info->MMIO;
- int i;
+ int i, j;
int idx;
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);
+
+#if 0
/* Select palette 0 (main CRTC) if using FP-enabled chip */
if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0);
+#endif
if (info->CurrentLayout.depth == 15) {
/* 15bpp mode. This sends 32 values. */
@@ -2092,6 +2179,8 @@
if (!R128MapMem(pScrn)) return FALSE;
pScrn->fbOffset = 0;
+ if(info->IsSecondary) pScrn->fbOffset = pScrn->videoRam * 1024;
+
#ifdef XF86DRI
info->fbX = 0;
info->fbY = 0;
@@ -2145,7 +2234,33 @@
info->CurrentLayout.pixel_bytes * 3 + 1023) / 1024);
info->directRenderingEnabled = FALSE;
} else {
- info->directRenderingEnabled = R128DRIScreenInit(pScreen);
+ 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
@@ -2588,6 +2703,32 @@
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;
+
+/* OUTREG(RADEON_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl);*/
+ OUTREGP(R128_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl,
+ R128_CRTC2_VSYNC_DIS |
+ R128_CRTC2_HSYNC_DIS |
+ R128_CRTC2_DISP_DIS);
+
+ OUTREG(R128_DAC_CNTL2, restore->dac2_cntl);
+ OUTREG(R128_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)
{
@@ -2685,6 +2826,80 @@
(restore->ppll_div_3 & R128_PPLL_POST3_DIV_MASK) >> 16));
}
+/* Write PLL2 registers. */
+static void R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
+{
+ R128InfoPtr info = R128PTR(pScrn);
+ unsigned char *R128MMIO = info->MMIO;
+
+ OUTPLLP(pScrn, 0x2d, 0x00, ~(0x03));
+
+
+ OUTREGP(R128_CLOCK_CNTL_INDEX, 0, R128_PLL2_DIV_SEL_MASK);
+
+
+ OUTPLLP(pScrn,
+ R128_P2PLL_CNTL,
+ R128_P2PLL_RESET
+ | R128_P2PLL_ATOMIC_UPDATE_EN
+ | R128_P2PLL_VGA_ATOMIC_UPDATE_EN,
+ 0xffff);
+
+ R128PLLWaitForReadUpdateComplete(pScrn);
+
+ while ( (INPLL(pScrn, R128_P2PLL_REF_DIV) & R128_P2PLL_REF_DIV_MASK) !=
+ (restore->p2pll_ref_div & R128_P2PLL_REF_DIV_MASK)) {
+ OUTPLLP(pScrn, R128_P2PLL_REF_DIV, restore->p2pll_ref_div, ~R128_P2PLL_REF_DIV_MASK);
+ }
+
+ R128PLLWriteUpdate(pScrn);
+
+ R128PLLWaitForReadUpdateComplete(pScrn);
+
+ while ( (INPLL(pScrn, R128_P2PLL_DIV_0) & R128_P2PLL_FB0_DIV_MASK) !=
+ (restore->p2pll_div_0 &
+R128_P2PLL_FB0_DIV_MASK)) {
+ OUTPLLP(pScrn, R128_P2PLL_DIV_0,
+ restore->p2pll_div_0, ~R128_P2PLL_FB0_DIV_MASK);
+ }
+
+ R128PLLWriteUpdate(pScrn);
+
+ R128PLLWaitForReadUpdateComplete(pScrn);
+
+ while ( (INPLL(pScrn, R128_P2PLL_DIV_0) & R128_P2PLL_POST0_DIV_MASK) !=
+ (restore->p2pll_div_0 & R128_P2PLL_POST0_DIV_MASK)) {
+ OUTPLLP(pScrn, R128_P2PLL_DIV_0,
+ restore->p2pll_div_0, ~R128_P2PLL_POST0_DIV_MASK);
+ }
+
+ R128PLLWriteUpdate(pScrn);
+
+ R128PLLWaitForReadUpdateComplete(pScrn);
+
+ OUTPLL(R128_HTOTAL2_CNTL, restore->htotal_cntl2);
+
+ R128PLLWriteUpdate(pScrn);
+
+ OUTPLLP(pScrn, R128_P2PLL_CNTL, 0,
+ ~(R128_P2PLL_RESET | R128_P2PLL_SLEEP));
+
+ R128TRACE(("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
+ restore->p2pll_ref_div,
+ restore->p2pll_div_0,
+ restore->htotal_cntl2,
+ INPLL(pScrn, RADEON_P2PLL_CNTL)));
+ R128TRACE(("Wrote: rd=%d, fd=%d, pd=%d\n",
+ restore->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK,
+ restore->p2pll_div_0 & RADEON_P2PLL_FB3_DIV_MASK,
+ (restore->p2pll_div_0 & RADEON_P2PLL_POST3_DIV_MASK) >>16));
+
+ OUTPLLP(pScrn, 0x2d, 0x03, ~(0x03));
+
+
+}
+
+
/* Write DDA registers. */
static void R128RestoreDDARegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
{
@@ -2695,6 +2910,8 @@
OUTREG(R128_DDA_ON_OFF, restore->dda_on_off);
}
+#if 0
+/* this is ifdef'ed out in radeon_driver.c */
/* Write palette data. */
static void R128RestorePalette(ScrnInfoPtr pScrn, R128SavePtr restore)
{
@@ -2703,30 +2920,121 @@
int i;
if (!restore->palette_valid) return;
-
+#if 0
+ /* new code should take care of this */
/* Select palette 0 (main CRTC) if using FP-enabled chip */
if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0);
OUTPAL_START(0);
for (i = 0; i < 256; i++) OUTPAL_NEXT_CARD32(restore->palette[i]);
+#endif
+
+/* from radeon_driver.c */
+ PAL_SELECT(1);
+ OUTPAL_START(0);
+ for (i = 0; i < 256; i++) {
+ R128WaitForFifo(pScrn, 32); /* delay */
+ OUTPAL_NEXT_CARD32(restore->palette2[i]);
+ }
+
+ PAL_SELECT(0);
+ OUTPAL_START(0);
+ for (i = 0; i < 256; i++) {
+ R128WaitForFifo(pScrn, 32); /* delay */
+ OUTPAL_NEXT_CARD32(restore->palette[i]);
+ }
+
}
+#endif
/* Write out state to define a new video mode. */
static void R128RestoreMode(ScrnInfoPtr pScrn, R128SavePtr restore)
{
R128InfoPtr info = R128PTR(pScrn);
+ DevUnion* pPriv;
+ R128EntPtr pR128Ent;
+ static R128SaveRec restore0;
+ /* for Non-dual head card, we don't have private field in the Entity*/
+ if(!info->HasCRTC2)
+ {
+ 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);
+ }
+
+ pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
+ gR128EntityIndex);
+ pR128Ent = pPriv->ptr;
+
R128TRACE(("R128RestoreMode(%p)\n", restore));
- R128RestoreCommonRegisters(pScrn, restore);
- R128RestoreCrtcRegisters(pScrn, restore);
- if (!(info->HasPanelRegs) || info->BIOSDisplay == R128_BIOS_DISPLAY_CRT){
- R128RestorePLLRegisters(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;
+
+ R128RestoreCrtcRegisters(pScrn, &restore0);
+ if((info0->isDFP) || (info0->HasPanelRegs))
+ {
+ R128RestoreFPRegisters(pScrn, &restore0);
+ }
+
+ R128RestorePLLRegisters(pScrn, &restore0);
+ pR128Ent->IsSecondaryRestored = FALSE;
+
+ }
+ }
+ else
+ {
+ R128RestoreCommonRegisters(pScrn, restore);
+ R128RestoreDDARegisters(pScrn, restore);
+ if(!pR128Ent->HasSecondary || pR128Ent->IsSecondaryRestored
+ || info->SwitchingMode)
+ {
+ pR128Ent->IsSecondaryRestored = FALSE;
+ R128RestoreCrtcRegisters(pScrn, restore);
+ if((info->isDFP) || (info->HasPanelRegs))
+ {
+ R128RestoreFPRegisters(pScrn, restore);
+ }
+ R128RestorePLLRegisters(pScrn, restore);
+ }
+ else
+ {
+ memcpy(&restore0, restore, sizeof(restore0));
+ pR128Ent->RestorePrimary = TRUE;
+ }
}
- R128RestoreDDARegisters(pScrn, restore);
- if (info->HasPanelRegs || info->isDFP)
- R128RestoreFPRegisters(pScrn, restore);
+#if 0
+ /* is this needed on R128 for dualhead? it's not used in the radeon driver */
R128RestorePalette(pScrn, restore);
+#endif
}
/* Read common registers. */
@@ -2789,6 +3097,25 @@
save->tmds_transmitter_cntl = INREG(R128_TMDS_TRANSMITTER_CNTL);
}
+/* Read CRTC2 registers. */
+static void R128SaveCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save)
+{
+ R128InfoPtr info = R128PTR(pScrn);
+ unsigned char *R128MMIO = info->MMIO;
+
+ save->dac2_cntl = INREG(R128_DAC_CNTL2);
+ save->disp_output_cntl = INREG(R128_DISP_OUTPUT_CNTL);
+
+ save->crtc2_gen_cntl = INREG(R128_CRTC2_GEN_CNTL);
+ save->crtc2_h_total_disp = INREG(R128_CRTC2_H_TOTAL_DISP);
+ save->crtc2_h_sync_strt_wid = INREG(R128_CRTC2_H_SYNC_STRT_WID);
+ save->crtc2_v_total_disp = INREG(R128_CRTC2_V_TOTAL_DISP);
+ save->crtc2_v_sync_strt_wid = INREG(R128_CRTC2_V_SYNC_STRT_WID);
+ save->crtc2_offset = INREG(R128_CRTC2_OFFSET);
+ save->crtc2_offset_cntl = INREG(R128_CRTC2_OFFSET_CNTL);
+ save->crtc2_pitch = INREG(R128_CRTC2_PITCH);
+}
+
/* Read PLL registers. */
static void R128SavePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save)
{
@@ -2806,6 +3133,23 @@
(save->ppll_div_3 & R128_PPLL_POST3_DIV_MASK) >> 16));
}
+/* Read PLL2 registers. */
+static void R128SavePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save)
+{
+ save->p2pll_ref_div = INPLL(pScrn, R128_P2PLL_REF_DIV);
+ save->p2pll_div_0 = INPLL(pScrn, R128_P2PLL_DIV_0);
+ save->htotal_cntl2 = INPLL(pScrn, R128_HTOTAL2_CNTL);
+
+ R128TRACE(("Read: 0x%08x 0x%08x 0x%08x\n",
+ save->p2pll_ref_div,
+ save->p2pll_div_0,
+ save->htotal_cntl2));
+ R128TRACE(("Read: rd=%d, fd=%d, pd=%d\n",
+ save->p2pll_ref_div & R128_P2PLL_REF_DIV_MASK,
+ save->p2pll_div_0 & R128_P2PLL_FB0_DIV_MASK,
+ (save->p2pll_div_0 & R128_P2PLL_POST0_DIV_MASK) >> 16));
+}
+
/* Read DDA registers. */
static void R128SaveDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save)
{
@@ -2836,13 +3180,24 @@
{
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);
+ R128InfoPtr info = R128PTR(pScrn);
+
+ 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);
+ /* this is indef'ed on radeon, what about R128? */
+ /* R128SavePalette(pScrn, save); */
+ }
R128TRACE(("R128SaveMode returns %p\n", save));
}
@@ -2860,17 +3215,24 @@
fbdevHWSave(pScrn);
return;
}
+
+ if(!info->IsSecondary)
+ {
vgaHWUnlock(hwp);
vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL); /* save mode, fonts, cmap */
vgaHWLock(hwp);
- R128SaveMode(pScrn, save);
+ /* R128SaveMode(pScrn, save); */
save->dp_datatype = INREG(R128_DP_DATATYPE);
save->gen_reset_cntl = INREG(R128_GEN_RESET_CNTL);
save->clock_cntl_index = INREG(R128_CLOCK_CNTL_INDEX);
save->amcgpio_en_reg = INREG(R128_AMCGPIO_EN_REG);
save->amcgpio_mask = INREG(R128_AMCGPIO_MASK);
+ }
+
+ R128SaveMode(pScrn, save);
+
}
/* Restore the original (text) mode. */
@@ -2894,12 +3256,43 @@
OUTREG(R128_GEN_RESET_CNTL, restore->gen_reset_cntl);
OUTREG(R128_DP_DATATYPE, restore->dp_datatype);
+#if 0
+ /* do any R128 cards need this? */
+ /* M6 card has trouble restoring text mode for its CRT.
+ Needs this workaround.*/
+ if(xf86IsEntityShared(pScrn->entityList[0]) && info->IsM6)
+ OUTREG(R128_DAC_CNTL2, restore->dac2_cntl);
+#endif
+
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);
+ }
+ }
+#if 0
+ /* this is ifdef'ed on Radeon, what about R128? */
R128WaitForVerticalSync(pScrn);
+#endif
R128Unblank(pScrn);
}
@@ -3058,6 +3451,99 @@
return TRUE;
}
+/* Define CRTC2 registers for requested video mode. */
+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 };
+
+ 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));
+
+ hsync_fudge = hsync_fudge_default[format-1];
+
+ save->crtc2_gen_cntl = (R128_CRTC2_EN
+ | R128_CRTC2_CRT2_ON
+ | (format << 8)
+ | ((mode->Flags & V_DBLSCAN)
+ ? R128_CRTC2_DBL_SCAN_EN
+ : 0)
+ | ((mode->Flags & V_INTERLACE)
+ ? R128_CRTC2_INTERLACE_EN
+ : 0));
+
+ save->dac2_cntl = info->SavedReg.dac2_cntl
+ /*| RADEON_DAC2_DAC2_CLK_SEL*/
+ | R128_DAC2_DAC_CLK_SEL;
+
+ save->crtc2_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0x3ff)
+ | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff) << 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 & 0x1fff)
+ | (hsync_wid << 16)
+ | ((mode->Flags & V_NHSYNC)
+ ? R128_CRTC_H_SYNC_POL
+ : R128_CRTC_H_SYNC_POL));
+
+#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_CRTC2_V_SYNC_POL
+ : R128_CRTC2_V_SYNC_POL));
+
+ save->crtc2_offset = 0;
+ save->crtc2_offset_cntl = 0;
+
+ save->crtc2_pitch = ((pScrn->displayWidth * pScrn->bitsPerPixel) +
+ ((pScrn->bitsPerPixel * 8) -1)) /
+ (pScrn->bitsPerPixel * 8);
+ save->crtc2_pitch |= save->crtc2_pitch << 16;
+
+ R128TRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n",
+ save->crtc2_pitch, pScrn->virtualX,
+ info->CurrentLayout.displayWidth));
+ return TRUE;
+}
+
/* Define CRTC registers for requested video mode. */
static void R128InitFPRegisters(R128SavePtr orig, R128SavePtr save,
DisplayModePtr mode, R128InfoPtr info)
@@ -3129,6 +3615,10 @@
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. */
+
+ /* does something need to be done here for dualhead mode?
+ The radeon drive just disables the CRT output for DFP.
+ Should I just disable it or leave the check in? */
if(!info->isDFP){
if (info->BIOSDisplay == R128_BIOS_DISPLAY_FP_CRT) {
@@ -3218,6 +3708,57 @@
}
+/* Define PLL2 registers for requested video mode. */
+static void R128InitPLL2Registers(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 */
+ { 16, 5 }, /* VCLK_SRC/16 */
+ { 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_2 = freq;
+ save->feedback_div_2 = R128Div(pll->reference_div
+ * save->pll_output_freq_2,
+ pll->reference_freq);
+ save->post_div_2 = 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->p2pll_div_0 = (save->feedback_div_2 | (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,
@@ -3354,10 +3895,21 @@
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 0
if (info->HasPanelRegs || info->isDFP)
R128InitFPRegisters(&info->SavedReg, save, mode, info);
+#endif
if(dot_clock > 0){
R128InitPLLRegisters(pScrn, save, &info->pll, dot_clock);
if (!R128InitDDARegisters(pScrn, save, &info->pll, info, mode))
@@ -3370,6 +3922,10 @@
save->dda_config = info->SavedReg.dda_config;
save->dda_on_off = info->SavedReg.dda_on_off;
}
+ }
+
+ if (info->HasPanelRegs || info->isDFP)
+ R128InitFPRegisters(&info->SavedReg, save, mode, info);
R128TRACE(("R128Init returns %p\n", save));
return TRUE;
@@ -3412,7 +3968,17 @@
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. */
@@ -3503,6 +4069,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);
}
@@ -3630,25 +4202,44 @@
int mask = (R128_CRTC_DISPLAY_DIS
| R128_CRTC_HSYNC_DIS
| R128_CRTC_VSYNC_DIS);
+ int mask2 = (R128_CRTC2_DISP_DIS |
+ R128_CRTC2_VSYNC_DIS |
+ R128_CRTC2_HSYNC_DIS);
switch (PowerManagementMode) {
case DPMSModeOn:
/* Screen: On; HSync: On, VSync: On */
- OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask);
+ if (info->IsSecondary)
+ OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~mask2);
+ else
+ OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask);
break;
case DPMSModeStandby:
/* Screen: Off; HSync: Off, VSync: On */
- OUTREGP(R128_CRTC_EXT_CNTL,
- R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS, ~mask);
+ if (info->IsSecondary)
+ OUTREGP(R128_CRTC2_GEN_CNTL,
+ R128_CRTC2_DISP_DIS | R128_CRTC2_HSYNC_DIS,
+ ~mask2);
+ else
+ OUTREGP(R128_CRTC_EXT_CNTL,
+ R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS, ~mask);
break;
case DPMSModeSuspend:
/* Screen: Off; HSync: On, VSync: Off */
- OUTREGP(R128_CRTC_EXT_CNTL,
- R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS, ~mask);
+ if (info->IsSecondary)
+ OUTREGP(R128_CRTC2_GEN_CNTL,
+ R128_CRTC2_DISP_DIS | R128_CRTC2_VSYNC_DIS,
+ ~mask2);
+ else
+ OUTREGP(R128_CRTC_EXT_CNTL,
+ R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS, ~mask);
break;
case DPMSModeOff:
/* Screen: Off; HSync: Off, VSync: Off */
- OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask);
+ if (info->IsSecondary)
+ OUTREGP(R128_CRTC2_GEN_CNTL, mask2, ~mask2);
+ else
+ OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask);
break;
}
}
--- ../ati.orig/r128.h 2002-12-16 11:19:10.000000000 -0500
+++ r128.h 2003-04-17 20:09:18.000000000 -0400
@@ -136,6 +136,16 @@
/* CRTC2 registers */
CARD32 crtc2_gen_cntl;
+ CARD32 dac2_cntl;
+ CARD32 disp_output_cntl;
+ CARD32 crtc2_h_total_disp;
+ CARD32 crtc2_h_sync_strt_wid;
+ CARD32 crtc2_v_total_disp;
+ CARD32 crtc2_v_sync_strt_wid;
+ CARD32 crtc2_offset;
+ CARD32 crtc2_offset_cntl;
+ CARD32 crtc2_pitch;
+
/* Flat panel registers */
CARD32 fp_crtc_h_total_disp;
CARD32 fp_crtc_v_total_disp;
@@ -160,6 +170,17 @@
CARD32 ppll_div_3;
CARD32 htotal_cntl;
+ /* Computed values for PLL2 */
+ CARD32 dot_clock_freq_2;
+ CARD32 pll_output_freq_2;
+ int feedback_div_2;
+ int post_div_2;
+
+ /* PLL2 registers */
+ CARD32 p2pll_ref_div;
+ CARD32 p2pll_div_0;
+ CARD32 htotal_cntl2;
+
/* DDA register */
CARD32 dda_config;
CARD32 dda_on_off;
@@ -167,6 +188,7 @@
/* Pallet */
Bool palette_valid;
CARD32 palette[256];
+ CARD32 palette2[256];
} R128SaveRec, *R128SavePtr;
typedef struct {
@@ -369,6 +391,14 @@
int textureSize;
int log2TexGran;
+/*
+ CARD32 frontPitchOffset;
+ CARD32 backPitchOffset;
+ CARD32 depthPitchOffset;
+
+ CARD32 dst_pitch_offset;
+*/
+
/* Saved scissor values */
CARD32 sc_left;
CARD32 sc_right;
@@ -397,6 +427,12 @@
I2CBusPtr pI2CBus;
CARD32 DDCReg;
+ /****** Added for dualhead support *******************/
+ BOOL HasCRTC2; /* VE/M6/M7 */
+ BOOL IsSecondary; /* second Screen */
+ BOOL UseCRT; /* force use CRT port as primary */
+ BOOL SwitchingMode;
+
} R128InfoRec, *R128InfoPtr;
#define R128WaitForFifo(pScrn, entries) \
--- ../ati.orig/r128_probe.c 2003-02-09 10:33:17.000000000 -0500
+++ r128_probe.c 2003-04-17 19:34:09.000000000 -0400
@@ -180,6 +180,8 @@
{ -1, -1, RES_UNDEFINED }
};
+int gR128EntityIndex = -1;
+
/* Return the options for supported chipset 'n'; NULL otherwise */
const OptionInfoRec *
R128AvailableOptions(int chipid, int busid)
@@ -216,7 +218,6 @@
int numDevSections, nATIGDev, nR128GDev;
int *usedChips;
GDevPtr *devSections, *ATIGDevs, *R128GDevs;
- EntityInfoPtr pEnt;
Bool foundScreen = FALSE;
int i;
@@ -262,11 +263,13 @@
if (flags & PROBE_DETECT)
foundScreen = TRUE;
else for (i = 0; i < numUsed; i++) {
- pEnt = xf86GetEntityInfo(usedChips[i]);
-
- if (pEnt->active) {
- ScrnInfoPtr pScrn = xf86AllocateScreen(drv, 0);
+ ScrnInfoPtr pScrn;
+ EntityInfoPtr pEnt;
+ pScrn = NULL;
+ if((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
+ R128PciChipsets, 0, 0, 0, 0, 0)))
+ {
#ifdef XFree86LOADER
if (!xf86LoadSubModule(pScrn, "r128")) {
@@ -295,11 +298,43 @@
foundScreen = TRUE;
- xf86ConfigActivePciEntity(pScrn, usedChips[i], R128PciChipsets,
- 0, 0, 0, 0, 0);
+ pEnt = xf86GetEntityInfo(usedChips[i]);
+
+ /* mobility cards support Dual-Head, mark the entity as sharable*/
+ if(pEnt->chipset == PCI_CHIP_RAGE128LE ||
+ pEnt->chipset == PCI_CHIP_RAGE128LF ||
+ pEnt->chipset == PCI_CHIP_RAGE128MF ||
+ pEnt->chipset == PCI_CHIP_RAGE128ML)
+ {
+ static int instance = 0;
+ DevUnion* pPriv;
+
+ xf86SetEntitySharable(usedChips[i]);
+ xf86SetEntityInstanceForScreen(pScrn,
+ pScrn->entityList[0], instance);
+
+ if(gR128EntityIndex < 0)
+ {
+ gR128EntityIndex = xf86AllocateEntityPrivateIndex();
+ pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
+ gR128EntityIndex);
+
+ if (!pPriv->ptr)
+ {
+ R128EntPtr pR128Ent;
+ pPriv->ptr = xnfcalloc(sizeof(R128EntRec), 1);
+ pR128Ent = pPriv->ptr;
+ pR128Ent->IsDRIEnabled = FALSE;
+ pR128Ent->BypassSecondary = FALSE;
+ pR128Ent->HasSecondary = FALSE;
+ pR128Ent->IsSecondaryRestored = FALSE;
+ }
+ }
+ instance++;
}
xfree(pEnt);
}
+ }
xfree(usedChips);
xfree(devSections);
--- ../ati.orig/r128_probe.h 2002-04-06 14:06:06.000000000 -0500
+++ r128_probe.h 2003-04-17 19:31:11.000000000 -0400
@@ -41,6 +41,22 @@
#include "xf86str.h"
+typedef struct
+{
+ Bool IsDRIEnabled;
+
+ Bool HasSecondary;
+ Bool BypassSecondary;
+ /*These two registers are used to make sure the CRTC2 is
+ retored before CRTC_EXT, otherwise it could lead to blank screen.*/
+ Bool IsSecondaryRestored;
+ Bool RestorePrimary;
+
+ ScrnInfoPtr pSecondaryScrn;
+ ScrnInfoPtr pPrimaryScrn;
+}R128EntRec, *R128EntPtr;
+
+
/* r128_probe.c */
extern const OptionInfoRec * R128AvailableOptions
FunctionPrototype((int, int));
--- ../ati.orig/r128_reg.h 2002-12-16 11:19:11.000000000 -0500
+++ r128_reg.h 2003-04-17 19:31:11.000000000 -0400
@@ -284,6 +284,7 @@
#define R128_CLOCK_CNTL_INDEX 0x0008
# define R128_PLL_WR_EN (1 << 7)
# define R128_PLL_DIV_SEL (3 << 8)
+# define R128_PLL2_DIV_SEL_MASK ~(3 << 8)
#define R128_CLR_CMP_CLR_3D 0x1a24
#define R128_CLR_CMP_CLR_DST 0x15c8
#define R128_CLR_CMP_CLR_SRC 0x15c4
@@ -374,15 +375,51 @@
#define R128_CRTC2_CRNT_FRAME 0x0314
#define R128_CRTC2_DEBUG 0x031c
#define R128_CRTC2_GEN_CNTL 0x03f8
+/* copied straight out of radeon_reg.h
+ someone with docs might want to double check these */
+# define R128_CRTC2_DBL_SCAN_EN (1 << 0)
+# define R128_CRTC2_INTERLACE_EN (1 << 1)
+# define R128_CRTC2_SYNC_TRISTAT (1 << 4)
+# define R128_CRTC2_HSYNC_TRISTAT (1 << 5)
+# define R128_CRTC2_VSYNC_TRISTAT (1 << 6)
+# define R128_CRTC2_CRT2_ON (1 << 7)
+# define R128_CRTC2_ICON_EN (1 << 15)
+# define R128_CRTC2_CUR_EN (1 << 16)
+# define R128_CRTC2_CUR_MODE_MASK (7 << 20)
+# define R128_CRTC2_DISP_DIS (1 << 23)
+# define R128_CRTC2_EN (1 << 25)
+# define R128_CRTC2_DISP_REQ_EN_B (1 << 26)
+# define R128_CRTC2_HSYNC_DIS (1 << 28)
+# define R128_CRTC2_VSYNC_DIS (1 << 29)
#define R128_CRTC2_GUI_TRIG_VLINE 0x0318
#define R128_CRTC2_H_SYNC_STRT_WID 0x0304
+# define R128_CRTC2_H_SYNC_STRT_PIX (0x07 << 0)
+# define R128_CRTC2_H_SYNC_STRT_CHAR (0x3ff << 3)
+# define R128_CRTC2_H_SYNC_STRT_CHAR_SHIFT 3
+# define R128_CRTC2_H_SYNC_WID (0x3f << 16)
+# define R128_CRTC2_H_SYNC_WID_SHIFT 16
+# define R128_CRTC2_H_SYNC_POL (1 << 23)
#define R128_CRTC2_H_TOTAL_DISP 0x0300
+# define R128_CRTC2_H_TOTAL (0x03ff << 0)
+# define R128_CRTC2_H_TOTAL_SHIFT 0
+# define R128_CRTC2_H_DISP (0x01ff << 16)
+# define R128_CRTC2_H_DISP_SHIFT 16
#define R128_CRTC2_OFFSET 0x0324
#define R128_CRTC2_OFFSET_CNTL 0x0328
+# define R128_CRTC2_TILE_EN (1 << 15)
#define R128_CRTC2_PITCH 0x032c
#define R128_CRTC2_STATUS 0x03fc
#define R128_CRTC2_V_SYNC_STRT_WID 0x030c
+# define R128_CRTC2_V_SYNC_STRT (0x7ff << 0)
+# define R128_CRTC2_V_SYNC_STRT_SHIFT 0
+# define R128_CRTC2_V_SYNC_WID (0x1f << 16)
+# define R128_CRTC2_V_SYNC_WID_SHIFT 16
+# define R128_CRTC2_V_SYNC_POL (1 << 23)
#define R128_CRTC2_V_TOTAL_DISP 0x0308
+# define R128_CRTC2_V_TOTAL (0x07ff << 0)
+# define R128_CRTC2_V_TOTAL_SHIFT 0
+# define R128_CRTC2_V_DISP (0x07ff << 16)
+# define R128_CRTC2_V_DISP_SHIFT 16
#define R128_CRTC2_VLINE_CRNT_VLINE 0x0310
#define R128_CRTC8_DATA 0x03d5 /* VGA, 0x3b5 */
#define R128_CRTC8_IDX 0x03d4 /* VGA, 0x3b4 */
@@ -392,6 +429,12 @@
#define R128_CUR_HORZ_VERT_POSN 0x0264
#define R128_CUR_OFFSET 0x0260
# define R128_CUR_LOCK (1 << 31)
+#define R128_CUR2_CLR0 0x036c
+#define R128_CUR2_CLR1 0x0370
+#define R128_CUR2_HORZ_VERT_OFF 0x0368
+#define R128_CUR2_HORZ_VERT_POSN 0x0364
+#define R128_CUR2_OFFSET 0x0360
+# define R128_CUR2_LOCK (1 << 31)
#define R128_DAC_CNTL 0x0058
# define R128_DAC_RANGE_CNTL (3 << 0)
@@ -401,6 +444,13 @@
# define R128_DAC_8BIT_EN (1 << 8)
# define R128_DAC_VGA_ADR_EN (1 << 13)
# define R128_DAC_MASK_ALL (0xff << 24)
+#define R128_DAC_CNTL2 0x007c
+# define R128_DAC2_DAC_CLK_SEL (1 << 0)
+# define R128_DAC2_DAC2_CLK_SEL (1 << 1)
+# define R128_DAC2_PALETTE_ACC_CTL (1 << 5)
+#define R128_DISP_OUTPUT_CNTL 0x0d64
+# define R128_DISP_DAC_SOURCE_MASK 0x03
+# define R128_DISP_DAC_SOURCE_CRTC2 0x01
#define R128_DAC_CRC_SIG 0x02cc
#define R128_DAC_DATA 0x03c9 /* VGA */
#define R128_DAC_MASK 0x03c6 /* VGA */
@@ -670,6 +720,7 @@
#define R128_HOST_DATA_LAST 0x17e0
#define R128_HOST_PATH_CNTL 0x0130
#define R128_HTOTAL_CNTL 0x0009 /* PLL */
+#define R128_HTOTAL2_CNTL 0x002e /* PLL */
#define R128_HW_DEBUG 0x0128
#define R128_HW_DEBUG2 0x011c
@@ -875,6 +926,19 @@
# define R128_PPLL_REF_DIV_MASK 0x03ff
# define R128_PPLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */
# define R128_PPLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */
+#define R128_P2PLL_CNTL 0x002a /* P2PLL */
+# define R128_P2PLL_RESET (1 << 0)
+# define R128_P2PLL_SLEEP (1 << 1)
+# define R128_P2PLL_ATOMIC_UPDATE_EN (1 << 16)
+# define R128_P2PLL_VGA_ATOMIC_UPDATE_EN (1 << 17)
+# define R128_P2PLL_ATOMIC_UPDATE_VSYNC (1 << 18)
+#define R128_P2PLL_DIV_0 0x002c
+# define R128_P2PLL_FB0_DIV_MASK 0x07ff
+# define R128_P2PLL_POST0_DIV_MASK 0x00070000
+#define R128_P2PLL_REF_DIV 0x002B /* PLL */
+# define R128_P2PLL_REF_DIV_MASK 0x03ff
+# define R128_P2PLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */
+# define R128_P2PLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */
#define R128_PWR_MNGMT_CNTL_STATUS 0x0f60 /* PCI */
#define R128_REG_BASE 0x0f18 /* PCI */
#define R128_REGPROG_INF 0x0f09 /* PCI */