Files
glide/glide3x/h5/minihwc/lin_mode.c
2018-08-05 12:02:59 +03:00

1544 lines
59 KiB
C

/*
** THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONL
** PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGH
** TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DF
** INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE
** DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com).
** THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
** EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR
** FULL TEXT OF THE NON-WARRANTY PROVISIONS.
**
** USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT T
** RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS I
** TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013
** AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FA
** SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS O
** THE UNITED STATES.
**
** COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVE
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if USE_XDGA_SWITCH
#include <X11/Xlib.h>
#include <X11/extensions/xf86dga.h>
#include <X11/extensions/xf86vmode.h>
static Display *dpy = 0;
static XDGADevice *dev = 0;
static XDGAMode *vidModes = 0;
#endif
#include <minihwc.h>
#include <hwcio.h>
#include "h3cinit.h"
#include "glide.h"
#include "fxglide.h"
#define CFG_FILE "/etc/conf.3dfx/voodoo3"
#if 1
#define LOG(x)
#else
#define LOG(x) \
do { \
FILE *dbg = fopen("debug.txt","a"); \
fprintf x ; \
fclose(dbg); \
} while(0);
#endif
static struct envitem_t {
char *env;
char *val;
struct envitem_t *next;
} *first = NULL;
static FxU32 saveVidProcCfg;
static FxU32 saveLfbMemoryConfig;
static FxU32 saveMiscInit0;
FxBool setVideoMode(void *hwnd,
int xRes,
int yRes,
int h3pixelSize,
int refresh,
void *hmon,
char *devicename)
{
GR_DCL_GC;
hwcBoardInfo *bInfo = gc->bInfo;
#if USE_XDGA_SWITCH
int eventbase, errorbase;
int i, numModes;
dpy=XOpenDisplay("");
if (!dpy) {
GDBG_INFO(80, "Failed to open X display\n");
return FXFALSE;
}
if (XDGAQueryExtension(dpy, &eventbase, &errorbase)) {
int major, minor;
XDGAQueryVersion(dpy, &major, &minor);
if (major>1 && minor<0) {
XCloseDisplay(dpy);
GDBG_INFO(80, "Banshee/V3 requires DGA version 1.x\n");
return FXFALSE;
}
}
vidModes = XDGAQueryModes(dpy, DefaultScreen(dpy), &numModes);
for (i=0; i<numModes; i++)
if ((vidModes[i].viewportWidth==xRes) &&
(vidModes[i].viewportHeight==yRes))
break;
if (i==numModes) {
GDBG_INFO(80, "Server doesn't support requested resolution\n");
vidModes=0;
return FXFALSE;
}
if ((dev = XDGASetMode(dpy, DefaultScreen(dpy), vidModes[i].num)) == NULL) {
GDBG_INFO(80, "Failed to set required video mode\n");
return FXFALSE;
}
XDGASync(dpy, False);
#else
if (!h3InitSetVideoMode(bInfo->regInfo.ioPortBase, xRes, yRes, refresh, FXTRUE)) {
GDBG_INFO(80, "Setmode failed -- unimplemented resolution\n");
return FXFALSE;
}
#endif
HWC_IO_LOAD(bInfo->regInfo, vidProcCfg, saveVidProcCfg);
HWC_IO_LOAD(bInfo->regInfo, lfbMemoryConfig, saveLfbMemoryConfig);
HWC_IO_LOAD(bInfo->regInfo, miscInit0, saveMiscInit0);
return FXTRUE;
} /* setVideoMode */
void resetVideo (void)
{
GR_DCL_GC;
hwcBoardInfo *bInfo = gc->bInfo;
HWC_IO_STORE(bInfo->regInfo, lfbMemoryConfig, saveLfbMemoryConfig);
HWC_IO_STORE(bInfo->regInfo, vidProcCfg, saveVidProcCfg);
HWC_IO_STORE(bInfo->regInfo, miscInit0, saveMiscInit0);
#if USE_XDGA_SWITCH
if (dpy) {
if (!XDGASetMode(dpy, DefaultScreen(dpy), 0)) {
GDBG_INFO(80, "Failed to return to previous video mode\n");
}
vidModes = NULL;
XCloseDisplay(dpy);
dpy = NULL;
XFree(dev);
}
#else
/* XXX to do */
#endif
GDBG_INFO(80, "resetVideo(): \n");
} /* resetVideo */
FxBool checkResolutions (FxBool *supportedByResolution, FxU32 stride, void *hmon)
{
/* [dBorca] this should be tied to cinit code (or at least DGA)
* FxU16 *h3InitFindVideoMode (FxU32 xRes, FxU32 yRes, FxU32 refresh)
*/
int res, ref;
for (res = GR_MIN_RESOLUTION; res <= GR_MAX_RESOLUTION; res++) {
for (ref = GR_MIN_REFRESH; ref <= GR_MAX_REFRESH; ref++) {
supportedByResolution[res * stride + ref] = FXTRUE;
}
}
return FXTRUE;
}
static void loadEnvFile (void)
{
FILE *file;
char data[256];
char *env, *val;
struct envitem_t *item;
FxBool sawError = FXFALSE;
static FxBool envinit = FXFALSE;
if (envinit) {
return;
}
envinit = FXTRUE;
if ((file = fopen(CFG_FILE, "r")) == NULL) {
return;
}
while (fgets(data, 255, file) != NULL) {
if ((*data=='#') || (*data=='\n')) {
continue;
}
if ((val = strchr(data, '=')) == NULL) {
if (!sawError) {
sawError = FXTRUE;
fprintf(stderr, "In config file " CFG_FILE ":\n");
}
fprintf(stderr, "Malformed line: %s\n", data);
continue;
}
*val++ = '\0';
env = data;
item = malloc(sizeof(struct envitem_t));
item->env = malloc(strlen(env)+1);
strcpy(item->env, env);
item->val = malloc(strlen(val)+1);
strcpy(item->val, val);
item->next = first;
first = item;
}
}
char *file_getenv (const char *a)
{
struct envitem_t *ptr;
char *result;
if ((result = getenv(a)) != NULL) {
return result;
}
loadEnvFile();
for (ptr = first; ptr != NULL; ptr = ptr->next) {
if (!strcmp(ptr->env, a)) {
return ptr->val;
}
}
return NULL;
}
#include "h3cinitdd.h"
#define CFG_READ(_chip, _offset) \
hwcReadConfigRegister(bInfo, _chip, offsetof(SstPCIConfigRegs, _offset))
#define CFG_WRITE(_chip, _offset, _value) \
hwcWriteConfigRegister(bInfo, _chip, offsetof(SstPCIConfigRegs, _offset), (_value))
static FxU32 memDecode[16] =
{
128*1024*1024,
256*1024*1024,
512*1024*1024,
1024*1024*1024,
64*1024*1024,
32*1024*1024,
16*1024*1024,
8*1024*1024,
4*1024*1024,
0,
0,
0,
0,
0,
0,
0
};
void
mapSlavePhysical(hwcBoardInfo *bInfo, FxU32 chipNum)
{
FxU32 cfgPciDecode, cmdStatus;
FxU32 masterMemBase0, masterMemBase1, masterIOBase;
FxU32 slaveMemBase0, slaveMemBase1, slaveIOBase;
FxU32 memBase0Decode, memBase1Decode;
FxU32 memBase0Mem, memBase1Mem;
LOG((dbg,"mapSlavePhysical(%d)\n",chipNum));
/* First, make sure the master has been reconfigured to only decode 32MB for memBase0,
* 64MB for memBase1, and 256B for ioBase0 */
cfgPciDecode = CFG_READ(0, cfgPciDecode);
/* Okay, first look at the master's current PCI decode for memBase0. If it's not set to
* 32MB then the board is still in it's powerup config and we need to fiddle with it. */
if((cfgPciDecode & SST_PCI_MEMBASE0_DECODE) != SST_PCI_MEMBASE0_DECODE_32MB) {
FxU32 numChips;
LOG((dbg,"fixing PCI decode on master\n"));
/* Now we have to try to glean how many chips we have and how much memory. We can figure out
* how many chips from looking at how much decode space memBase0 was strapped for. */
memBase0Decode = (cfgPciDecode & SST_PCI_MEMBASE0_DECODE) >> SST_PCI_MEMBASE0_DECODE_SHIFT;
memBase1Decode = (cfgPciDecode & SST_PCI_MEMBASE1_DECODE) >> SST_PCI_MEMBASE1_DECODE_SHIFT;
memBase0Mem = memDecode[memBase0Decode];
memBase1Mem = memDecode[memBase1Decode];
/* Calc number of chips... */
/* Hack... some early A1 boards are still strapped for 256MB for memBase0 */
if(memBase0Decode == 256*1024*1024) {
memBase0Decode = 64*1024*1024;
}
numChips = memBase0Decode / (32*1024*1024);
memBase1Decode = SST_PCI_MEMBASE1_DECODE_64MB;
/* Okay, remap master to make room for slaves. */
cfgPciDecode &= ~(SST_PCI_MEMBASE0_DECODE | SST_PCI_MEMBASE1_DECODE | SST_PCI_IOBASE0_DECODE);
cfgPciDecode |= (SST_PCI_MEMBASE0_DECODE_32MB | SST_PCI_IOBASE0_DECODE_256);
cfgPciDecode |= memBase1Decode;
CFG_WRITE(0, cfgPciDecode, cfgPciDecode);
}
/* Now figure out the master's physical addresses, masking off bits we don't care about. */
masterMemBase0 = CFG_READ(0, memBaseAddr0) & ~0xf;
masterMemBase1 = CFG_READ(0, memBaseAddr1) & ~0xf;
masterIOBase = CFG_READ(0, ioBaseAddr) & ~0xf;
LOG((dbg,"masterMemBase0: %08lx (%dMB)\n",masterMemBase0,
memDecode[(cfgPciDecode & SST_PCI_MEMBASE0_DECODE) >> SST_PCI_MEMBASE0_DECODE_SHIFT] / 1024*1024));
LOG((dbg,"masterMemBase1: %08lx (%dMB)\n",masterMemBase1,
memDecode[(cfgPciDecode & SST_PCI_MEMBASE1_DECODE) >> SST_PCI_MEMBASE1_DECODE_SHIFT] / 1024*1024));
LOG((dbg,"masterIOBase: %08lx\n",masterIOBase));
/* Calculate how much memory space the master uses for memBase1. */
memBase1Decode = (cfgPciDecode & SST_PCI_MEMBASE1_DECODE) >> SST_PCI_MEMBASE1_DECODE_SHIFT;
memBase1Mem = memDecode[memBase1Decode];
/* Calculate desired slave addresses. */
slaveMemBase0 = masterMemBase0 + 32*1024*1024*chipNum;
/* Note: All slaves share the same memBase1 address space. */
slaveMemBase1 = masterMemBase1 + memBase1Mem;
/* Note: Slaves share IO space with the master, but have I/O cycles turned off. */
slaveIOBase = masterIOBase; /* + 256*chipNum; */
LOG((dbg,"slaveMemBase0: %08lx\n",slaveMemBase0));
LOG((dbg,"slaveMemBase1: %08lx\n",slaveMemBase1));
LOG((dbg,"slaveIOBase: %08lx\n",slaveIOBase));
/* Enable init register writes */
CFG_WRITE(chipNum, cfgInitEnable_FabID,
(SST_ENABLE_HARDWARE_INIT_WRITES |
SST_ENABLE_PCI_FIFO_WRITES |
SST_ENABLE_BASE_ADDR_WRITES) << 8);
/* Make sure slaves are only going to decode what we want them to. The slaves always decode
* the same amount of memory that the master does, but some of the slave memory areas overlap. */
/* Make sure we set up the right snoop enable stuff too */
cfgPciDecode &= ~(SST_SNOOP_MEMBASE0_DECODE | SST_SNOOP_MEMBASE1_DECODE);
cfgPciDecode |= SST_SNOOP_MEMBASE0_DECODE_32MB;
cfgPciDecode |= memBase1Decode << SST_SNOOP_MEMBASE1_DECODE_SHIFT;
CFG_WRITE(chipNum, cfgPciDecode, cfgPciDecode);
/* Program slaves for their new home. */
CFG_WRITE(chipNum, memBaseAddr0, slaveMemBase0);
CFG_WRITE(chipNum, memBaseAddr1, slaveMemBase1);
CFG_WRITE(chipNum, ioBaseAddr, slaveIOBase);
/* Enable memory decode on slave, but keep IO disabled. */
cmdStatus = CFG_READ(chipNum, status_command);
cmdStatus &= ~1;
cmdStatus |= 2;
CFG_WRITE(chipNum, status_command, cmdStatus);
LOG((dbg,"mapSlavePhysical(%d) done\n",chipNum));
}
/* This assumes that the slave has been mapped in already. */
void
initSlave(hwcBoardInfo *bInfo, FxU32 chipNum)
{
FxU32 pciInit0, pllCtrl1;
FxU32 dramInit0, dramInit1;
FxU32 miscInit0, miscInit1;
FxU32 tmuGbeInit;
FxU32 cmdStatus;
LOG((dbg,"initSlave(%d)\n",chipNum));
/* Copy over pll & memory timings, etc. */
HWC_IO_LOAD(bInfo->regInfo, pllCtrl1, pllCtrl1);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, pllCtrl1, pllCtrl1);
HWC_IO_LOAD(bInfo->regInfo, dramInit0, dramInit0);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, dramInit0, dramInit0);
HWC_IO_LOAD(bInfo->regInfo, dramInit1, dramInit1);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, dramInit1, dramInit1);
HWC_IO_LOAD(bInfo->regInfo, pciInit0, pciInit0);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, pciInit0, pciInit0);
HWC_IO_LOAD(bInfo->regInfo, miscInit0, miscInit0);
miscInit0 &= ~BIT(30);
HWC_IO_STORE(bInfo->regInfo, miscInit0, miscInit0);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, miscInit0, miscInit0);
HWC_IO_LOAD(bInfo->regInfo, miscInit1, miscInit1);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, miscInit1, miscInit1);
HWC_IO_LOAD(bInfo->regInfo, tmuGbeInit, tmuGbeInit);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, tmuGbeInit, tmuGbeInit);
/* Init DRAM mode stuff */
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, dramData, 0x000000037);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, dramCommand, 0x10d);
/* Disable master IO */
cmdStatus = CFG_READ(0, status_command);
cmdStatus &= ~1;
CFG_WRITE(0, status_command, cmdStatus);
/* Enable slave IO */
cmdStatus = CFG_READ(chipNum, status_command);
cmdStatus |= 1;
CFG_WRITE(chipNum, status_command, cmdStatus);
/* Reset everything */
h3InitResetAll(bInfo->regInfo.slaveIOBase[chipNum-1]);
/* Init VGA (no legacy decode) */
h3InitVga(bInfo->regInfo.slaveIOPortBase[chipNum-1], FXFALSE);
/* Disable slave IO */
cmdStatus = CFG_READ(chipNum, status_command);
cmdStatus &= ~1;
CFG_WRITE(chipNum, status_command, cmdStatus);
/* Enable master IO */
cmdStatus = CFG_READ(0, status_command);
cmdStatus |= 1;
CFG_WRITE(0, status_command, cmdStatus);
{
FxU32 status, vgaInit0, vgaInit1;
HWC_IO_LOAD_SLAVE(chipNum, bInfo->regInfo, status, status);
HWC_IO_LOAD_SLAVE(chipNum, bInfo->regInfo, vgaInit0, vgaInit0);
HWC_IO_LOAD_SLAVE(chipNum, bInfo->regInfo, vgaInit1, vgaInit1);
LOG((dbg,"initSlave(%d) done. slave status: %08lx vgaInit0: %08lx vgaInit1: %08lx\n",chipNum, status, vgaInit0, vgaInit1));
}
}
static FxU8 vgaattr[] = {0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x0F, 0x00};
/* The standard mode table has 24 entries, but the first 3 are x, y and refresh.
* We don't care about those here. The default values (0-21) are just to serve
* as a reference for the comments... they will be blown away the first time we
* fill out the table. */
static FxU16 modeData[21] =
{
0, /* CRTC (0xd4) Index 0x00 - Horizontal Total */
1, /* CRTC (0xd4) Index 0x01 - Horizontal Display Enable End */
2, /* CRTC (0xd4) Index 0x02 - Start Horizontal Blanking */
3, /* CRTC (0xd4) Index 0x03 - End Horizontal Blanking */
4, /* CRTC (0xd4) Index 0x04 - Start Horizontal Sync */
5, /* CRTC (0xd4) Index 0x05 - End Horzontal Sync */
6, /* CRTC (0xd4) Index 0x06 - Vertical Total */
7, /* CRTC (0xd4) Index 0x07 - Overflow */
8, /* CRTC (0xd4) Index 0x09 - Maximum Scan Line */
9, /* CRTC (0xd4) Index 0x10 - Vertical Retrace Start */
10, /* CRTC (0xd4) Index 0x11 - Vertical Retrace End */
11, /* CRTC (0xd4) Index 0x12 - Vertical Display Enable End */
12, /* CRTC (0xd4) Index 0x15 - Start Vertical Blank */
13, /* CRTC (0xd4) Index 0x16 - End Vertical Blank */
14, /* CRTC (0xd4) Index 0x1a - Horizontal Extension Register */
15, /* CRTC (0xd4) Index 0x1b - Vertical Extension Register */
16, /* Miscellaneous Output (Written to port 0xc2, but read from 0xcc) */
17, /* Sequencer (0xc4) Index 0x01 */
18, /* pllCtrl0 - Low byte */
19, /* pllCtrl0 - High byte */
20 /* 2X Mode */
};
#define GET_CRTC_INDEX(_srcindex, _dstindex) \
ISET8PHYS(0x0d4, _srcindex); \
modeData[_dstindex] = IGET8PHYS(0x0d5);
void
buildVideoModeData(hwcBoardInfo *bInfo)
{
/* Snarf all VGA data we need from the master */
FxU32 regBase, pllCtrl0;
regBase = bInfo->regInfo.ioPortBase;
/* CRTC values */
GET_CRTC_INDEX(0x00, 0);
GET_CRTC_INDEX(0x01, 1);
GET_CRTC_INDEX(0x02, 2);
GET_CRTC_INDEX(0x03, 3);
GET_CRTC_INDEX(0x04, 4);
GET_CRTC_INDEX(0x05, 5);
GET_CRTC_INDEX(0x06, 6);
GET_CRTC_INDEX(0x07, 7);
GET_CRTC_INDEX(0x09, 8);
GET_CRTC_INDEX(0x10, 9);
GET_CRTC_INDEX(0x11, 10);
GET_CRTC_INDEX(0x12, 11);
GET_CRTC_INDEX(0x15, 12);
GET_CRTC_INDEX(0x16, 13);
GET_CRTC_INDEX(0x1a, 14);
GET_CRTC_INDEX(0x1b, 15);
/* Miscellaneous output */
modeData[16] = IGET8PHYS(0x0cc);
/* Sequencer */
ISET8PHYS(0x0c4, 0x01);
modeData[17] = IGET8PHYS(0x0c5);
/* pllCtrl0 */
pllCtrl0 = IGET32(pllCtrl0);
modeData[18] = (FxU16)(pllCtrl0 & 0xFF);
modeData[19] = (FxU16)((pllCtrl0 >> 8) & 0xFF);
/* 2X Mode */
modeData[20] = (FxU16)IGET32(dacMode);
{
FxU32 i;
for(i = 0; i < 21; i++) {
LOG((dbg,"modeData[%d]: %02lx\n",i,modeData[i]));
}
}
}
void
setVideoModeSlave(
FxU32 regBase) // regBase of the slave
{
FxU16 i;
FxU8 garbage;
FxU32 vidProcCfg;
FxU16 *rs = modeData;
//
// MISC REGISTERS
// This register gets programmed first since the Mono/ Color
// selection needs to be made.
//
// Sync polarities
// Also force the programmable clock to be used with bits 3&2
//
LOG((dbg,"setVideoModeSlave(%04lx)\n",regBase));
LOG((dbg,"motherboard enable: %02lx\n",IGET8PHYS(0xc3)));
ISET8PHYS(0xc2, rs[16] | BIT(0));
//
// CRTC REGISTERS
// First Unlock CRTC, then program them
//
// Mystical VGA Magic
ISET16PHYS(0x0d4, 0x11);
ISET16PHYS(0x0d4, (rs[0] << 8) | 0x00);
ISET16PHYS(0x0d4, (rs[1] << 8) | 0x01);
ISET16PHYS(0x0d4, (rs[2] << 8) | 0x02);
ISET16PHYS(0x0d4, (rs[3] << 8) | 0x03);
ISET16PHYS(0x0d4, (rs[4] << 8) | 0x04);
ISET16PHYS(0x0d4, (rs[5] << 8) | 0x05);
ISET16PHYS(0x0d4, (rs[6] << 8) | 0x06);
ISET16PHYS(0x0d4, (rs[7] << 8) | 0x07);
ISET16PHYS(0x0d4, (rs[8] << 8) | 0x09);
ISET16PHYS(0x0d4, (rs[9] << 8) | 0x10);
ISET16PHYS(0x0d4, (rs[10] << 8) | 0x11);
ISET16PHYS(0x0d4, (rs[11] << 8) | 0x12);
ISET16PHYS(0x0d4, (rs[12] << 8) | 0x15);
ISET16PHYS(0x0d4, (rs[13] << 8) | 0x16);
ISET16PHYS(0x0d4, (rs[14] << 8) | 0x1a);
ISET16PHYS(0x0d4, (rs[15] << 8) | 0x1b);
//
// Enable Sync Outputs
//
ISET16PHYS(0x0d4, (0x80 << 8) | 0x17);
//
// VIDCLK (32 bit access only!)
// Set the Video Clock to the correct frequency
//
ISET32(pllCtrl0, (rs[19] << 8) | rs[18]);
//
// dacMode (32 bit access only!)
// (sets up 1x mode or 2x mode)
//
ISET32(dacMode, rs[20]);
//
// the 1x / 2x bit must also be set in vidProcConfig to properly
// enable 1x / 2x mode
//
vidProcCfg = IGET32(vidProcCfg);
vidProcCfg &= ~(SST_VIDEO_2X_MODE_EN | SST_HALF_MODE);
if (rs[20])
vidProcCfg |= SST_VIDEO_2X_MODE_EN;
ISET32(vidProcCfg, vidProcCfg);
//
// SEQ REGISTERS
// set run mode in the sequencer (not reset)
//
// make sure bit 5 == 0 (i.e., screen on)
//
ISET16PHYS(0x0c4, ((rs[17] & ((FxU16) ~BIT(5))) << 8) | 0x1 );
ISET16PHYS(0x0c4, ( 0x3 << 8) | 0x0 );
//
// turn off VGA's screen refresh, as this function only sets extended
// video modes, and the VGA screen refresh eats up performance
// (10% difference in screen to screen blits!). This code is not in
// the perl, but should stay here unless specifically decided otherwise
//
ISET32(vgaInit0, IGET32(vgaInit0)|BIT(12) );
//
// Make sure attribute index register is initialized
//
garbage = IGET8PHYS(0x0da); // return value not used
for (i = 0; i <= 19; i++)
{
ISET8PHYS(0xc0, i);
ISET8PHYS(0xc0, vgaattr[i]);
}
ISET8PHYS(0xc0, 0x34);
ISET8PHYS(0xda, 0);
LOG((dbg,"setVideoModeSlave(%04lx) done\n",regBase));
} // h3InitSetVideoMode
/* This code is mostly based on the Win9x sliaa.c code. */
void hwcSetSLIAAMode(hwcBoardInfo *bInfo,
FxU32 sliEnable,
FxU32 aaEnable,
FxU32 analogSLI,
FxU32 sliBandHeight,
FxU32 totalMem,
FxU32 numChips,
FxU32 aaSampleHigh,
FxU32 aaColorBuffStart,
FxU32 aaDepthBuffStart,
FxU32 aaDepthBuffEnd,
FxU32 bpp)
{
FxU32 chipNum, temp;
FxU32 numChipsLog2;
FxU32 memBase0, memBase1;
FxU32 sliBandHeightLog2, sliRenderMask, sliCompareMask, sliScanMask;
FxU32 cmdStatus;
FxU32 vid2xMode;
LOG((dbg,"hwcSetSLIAAMode() begin\n"));
/* Enable AA and/or SLI */
if(sliEnable || aaEnable) {
/* First, init all chips */
for(chipNum = 1; chipNum < numChips; chipNum++) {
initSlave(bInfo, chipNum);
}
/* Grab video mode data from master. */
buildVideoModeData(bInfo);
/* Now set up video modes */
for(chipNum = 1; chipNum < numChips; chipNum++) {
/* Disable master IO */
cmdStatus = CFG_READ(0, status_command);
cmdStatus &= ~1;
CFG_WRITE(0, status_command, cmdStatus);
/* Enable slave IO */
cmdStatus = CFG_READ(chipNum, status_command);
cmdStatus |= 1;
CFG_WRITE(chipNum, status_command, cmdStatus);
setVideoModeSlave(bInfo->regInfo.slaveIOPortBase[chipNum-1]);
/* Disable slave IO */
cmdStatus = CFG_READ(chipNum, status_command);
cmdStatus &= ~1;
CFG_WRITE(chipNum, status_command, cmdStatus);
/* Enable master IO */
cmdStatus = CFG_READ(0, status_command);
cmdStatus |= 1;
CFG_WRITE(0, status_command, cmdStatus);
/* Copy over video processor config registers */
HWC_IO_LOAD(bInfo->regInfo, vidScreenSize, temp);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, vidScreenSize, temp);
/* Make sure video processor is reset so the size change takes effect. */
HWC_IO_LOAD(bInfo->regInfo, vidProcCfg, temp);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, vidProcCfg, temp & ~1);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, vidProcCfg, temp | 1);
/* Note: We don't set any start addresses here because it's done as part
* of the 3D init stuff... */
HWC_IO_LOAD(bInfo->regInfo, vidOverlayStartCoords, temp);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, vidOverlayStartCoords, temp);
HWC_IO_LOAD(bInfo->regInfo, vidOverlayEndScreenCoord, temp);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, vidOverlayEndScreenCoord, temp);
HWC_IO_LOAD(bInfo->regInfo, vidOverlayDudxOffsetSrcWidth, temp);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, vidOverlayDudxOffsetSrcWidth, temp);
HWC_IO_LOAD(bInfo->regInfo, vidDesktopOverlayStride, temp);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, vidDesktopOverlayStride, temp);
HWC_IO_LOAD(bInfo->regInfo, vidOverlayDudx, temp);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, vidOverlayDudx, temp);
HWC_IO_LOAD(bInfo->regInfo, vidMaxRGBDelta, temp);
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, vidMaxRGBDelta, temp);
}
/* Calculate Log2 of the SLI band height */
switch (sliBandHeight) {
case 2: sliBandHeightLog2 = 1;
break;
case 4: sliBandHeightLog2 = 2;
break;
case 8: sliBandHeightLog2 = 3;
break;
case 16: sliBandHeightLog2 = 4;
break;
case 32: sliBandHeightLog2 = 5;
break;
case 64: sliBandHeightLog2 = 6;
break;
case 128: sliBandHeightLog2 = 7;
break;
}
LOG((dbg,"sliBandHeight: %d log2: %d\n",sliBandHeight, sliBandHeightLog2));
/* Calculate Log2 of the number of chips */
switch(numChips) {
case 1: numChipsLog2 = 0;
break;
case 2: numChipsLog2 = 1;
break;
case 4: numChipsLog2 = 2;
break;
case 8: numChipsLog2 = 3;
break;
}
LOG((dbg,"numChips: %d log2: %d\n",numChips, numChipsLog2));
memBase0 = bInfo->pciInfo.pciBaseAddr[0] & ~0xf;
memBase1 = bInfo->pciInfo.pciBaseAddr[1] & ~0xf;
LOG((dbg,"memBase0: %08lx\n",memBase0));
LOG((dbg,"memBase1: %08lx\n",memBase1));
/* Now on to the MUCH nastier backend stuff... */
for(chipNum = 0; chipNum < numChips; chipNum++) {
/* Is 2x video mode enabled? */
HWC_IO_LOAD(bInfo->regInfo, vidProcCfg, temp);
vid2xMode = (temp & SST_VIDEO_2X_MODE_EN);
/* Set up pciInit0 and tmuGbeInit */
if(chipNum == 0) {
HWC_IO_LOAD(bInfo->regInfo, pciInit0, temp);
temp = (temp & ~(SST_PCI_RETRY_INTERVAL|SST_PCI_FORCE_FB_HIGH)) |
SST_PCI_READ_WS | SST_PCI_WRITE_WS;
HWC_IO_STORE(bInfo->regInfo, pciInit0, temp);
LOG((dbg,"master pciInit0: %08lx\n",temp));
HWC_IO_LOAD(bInfo->regInfo, tmuGbeInit, temp);
temp = (temp & ~(SST_AA_CLK_DELAY | SST_AA_CLK_INVERT)) |
(0x02 << SST_AA_CLK_DELAY_SHIFT) | SST_AA_CLK_INVERT;
HWC_IO_STORE(bInfo->regInfo, tmuGbeInit, temp);
LOG((dbg,"master tmuGbeInit: %08lx\n",temp));
/* Dump out any other registers we want to look at... */
HWC_IO_LOAD(bInfo->regInfo, miscInit0, temp);
LOG((dbg,"master miscInit0: %08lx\n",temp));
HWC_IO_LOAD(bInfo->regInfo, miscInit1, temp);
LOG((dbg,"master miscInit1: %08lx\n",temp));
} else {
HWC_IO_LOAD_SLAVE(chipNum, bInfo->regInfo, pciInit0, temp);
temp = (temp & ~(SST_PCI_RETRY_INTERVAL|SST_PCI_FORCE_FB_HIGH)) |
SST_PCI_READ_WS | SST_PCI_WRITE_WS;
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, pciInit0, temp);
LOG((dbg,"slave pciInit0: %08lx\n",temp));
HWC_IO_LOAD_SLAVE(chipNum, bInfo->regInfo, tmuGbeInit, temp);
temp = (temp & ~(SST_AA_CLK_DELAY | SST_AA_CLK_INVERT)) |
(0x02 << SST_AA_CLK_DELAY_SHIFT) | SST_AA_CLK_INVERT;
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, tmuGbeInit, temp);
LOG((dbg,"slave tmuGbeInit: %08lx\n",temp));
HWC_IO_LOAD_SLAVE(chipNum, bInfo->regInfo, miscInit0, temp);
LOG((dbg,"slave miscInit0: %08lx\n",temp));
HWC_IO_LOAD_SLAVE(chipNum, bInfo->regInfo, miscInit1, temp);
LOG((dbg,"slave miscInit1: %08lx\n",temp));
}
/* Set up buffer swap control and snooping */
if(numChips > 1) {
/* Buffer swapping */
temp = CFG_READ(chipNum, cfgInitEnable_FabID) >> 8;
LOG((dbg,"cfgInitEnable rd0: %08lx\n",temp << 8));
temp &= ~SST_SWAP_MASTER;
temp |= (SST_SWAPBUFFER_ALGORITHM | (chipNum == 0 ? SST_SWAP_MASTER : 0));
LOG((dbg,"cfgInitEnable wr0: %08lx\n",temp << 8));
CFG_WRITE(chipNum, cfgInitEnable_FabID, temp << 8);
/* Enable snooping */
if(chipNum == 0) {
temp = CFG_READ(chipNum, cfgInitEnable_FabID) >> 8;
temp |= SST_ADDRESS_SNOOP_ENABLE;
CFG_WRITE(chipNum, cfgInitEnable_FabID, temp << 8);
} else {
temp = CFG_READ(chipNum, cfgInitEnable_FabID) >> 8;
LOG((dbg,"cfgInitEnable rd1: %08lx\n",temp << 8));
temp &= ~SST_MEMBASE0_SNOOP;
LOG((dbg,"Snoop cleared: %08lx\n",temp << 8));
temp |= (SST_ADDRESS_SNOOP_ENABLE | SST_MEMBASE0_SNOOP_ENABLE | SST_MEMBASE1_SNOOP_ENABLE | SST_ADDRESS_SNOOP_SLAVE |
SST_INIT_REGISTER_SNOOP_ENABLE |
(((memBase0>>22) & 0x3ff) << SST_MEMBASE0_SNOOP_SHIFT) |
((numChips > 2) ? SST_QUICK_SAMPLING : 0x0));
LOG((dbg,"cfgInitEnable wr1: %08lx\n",temp << 8));
CFG_WRITE(chipNum, cfgInitEnable_FabID, temp << 8);
temp = CFG_READ(chipNum, cfgPciDecode);
LOG((dbg,"cfgPciDecode rd: %08lx\n",temp));
temp &= ~SST_MEMBASE1_SNOOP;
temp |= ((memBase1 >> 22) & 0x3ff) << SST_MEMBASE1_SNOOP_SHIFT;
LOG((dbg,"cfgPciDecode wr: %08lx\n",temp));
CFG_WRITE(chipNum, cfgPciDecode, temp);
}
}
/* cfgSliLfbCtrl */
if(sliEnable && (!aaEnable || !aaSampleHigh)) {
if(numChips == 4 && aaEnable && !aaSampleHigh && analogSLI) {
/* 4 chip 2 sample AA. two 2-way SLI units with 1 subsample per SLI unit */
sliRenderMask = ((numChips >> 1) - 1) << sliBandHeightLog2;
sliCompareMask = (chipNum >> 1) << sliBandHeightLog2;
sliScanMask = sliBandHeight - 1;
temp = (sliRenderMask << SST_SLI_LFB_RENDERMASK_SHIFT) |
(sliCompareMask << SST_SLI_LFB_COMPAREMASK_SHIFT) |
(sliScanMask << SST_SLI_LFB_SCANMASK_SHIFT) |
((numChipsLog2-1) << SST_SLI_LFB_NUMCHIPS_LOG2_SHIFT) |
SST_SLI_LFB_CPU_WRITE_ENABLE |
SST_SLI_LFB_DISPATCH_WRITE_ENABLE |
SST_SLI_LFB_READ_ENABLE;
CFG_WRITE(chipNum, cfgSliLfbCtrl, temp);
} else {
/* No aa or 2 sample AA w/SLI */
sliRenderMask = (numChips - 1) << sliBandHeightLog2;
sliCompareMask = chipNum << sliBandHeightLog2;
sliScanMask = sliBandHeight - 1;
temp = (sliRenderMask << SST_SLI_LFB_RENDERMASK_SHIFT) |
(sliCompareMask << SST_SLI_LFB_COMPAREMASK_SHIFT) |
(sliScanMask << SST_SLI_LFB_SCANMASK_SHIFT) |
(numChipsLog2 << SST_SLI_LFB_NUMCHIPS_LOG2_SHIFT) |
SST_SLI_LFB_CPU_WRITE_ENABLE |
SST_SLI_LFB_DISPATCH_WRITE_ENABLE |
SST_SLI_LFB_READ_ENABLE;
CFG_WRITE(chipNum, cfgSliLfbCtrl, temp);
}
} else if(!sliEnable && aaEnable) {
/* SLI disabled, AA enabled */
CFG_WRITE(chipNum, cfgSliLfbCtrl, 0);
} else {
/* SLI enabled, AA enabled, 4 sample AA enabled */
sliRenderMask = ((numChips >> 1) - 1) << sliBandHeightLog2;
sliCompareMask = (chipNum >> 1) << sliBandHeightLog2;
sliScanMask = sliBandHeight - 1;
temp = (sliRenderMask << SST_SLI_LFB_RENDERMASK_SHIFT) |
(sliCompareMask << SST_SLI_LFB_COMPAREMASK_SHIFT) |
(sliScanMask << SST_SLI_LFB_SCANMASK_SHIFT) |
((numChipsLog2-1) << SST_SLI_LFB_NUMCHIPS_LOG2_SHIFT) |
SST_SLI_LFB_CPU_WRITE_ENABLE |
SST_SLI_LFB_DISPATCH_WRITE_ENABLE |
SST_SLI_LFB_READ_ENABLE;
CFG_WRITE(chipNum, cfgSliLfbCtrl, temp);
}
/* cfgSliAATiledAperture */
if(sliEnable && !aaEnable) {
/* Do nothing */
} else {
/* AA is enabled */
FxU32 format;
switch(bpp) {
case 15: format = SST_AA_LFB_READ_FORMAT_15BPP;
break;
case 16: format = SST_AA_LFB_READ_FORMAT_16BPP;
break;
case 32: format = SST_AA_LFB_READ_FORMAT_32BPP;
break;
}
temp = (aaColorBuffStart << SST_SECONDARY_BUFFER_BASE_SHIFT) |
SST_AA_LFB_CPU_WRITE_ENABLE |
SST_AA_LFB_DISPATCH_WRITE_ENABLE |
format |
(aaSampleHigh ? SST_AA_LFB_RD_DIVIDE_BY_FOUR : 0x0);
CFG_WRITE(chipNum, cfgAALfbCtrl, temp);
temp = ((aaDepthBuffStart >> 12) << SST_AA_DEPTH_BUFFER_APERTURE_BEGIN_SHIFT) |
((aaDepthBuffEnd >> 12) << SST_AA_DEPTH_BUFFER_APERTURE_END_SHIFT);
CFG_WRITE(chipNum, cfgAADepthBufferAperture, temp);
}
/* Set up vga_vsync_offset field in cfgSliAAMisc */
if((numChips > 1) && (chipNum > 0) && (aaEnable || sliEnable)) {
FxU32 vsyncOffsetPixels, vsyncOffsetChars, vsyncOffsetHXtra;
if((analogSLI &&
!((numChips == 4) && sliEnable && aaEnable && !aaSampleHigh && analogSLI && (chipNum != 2)) &&
!((numChips == 4) && !sliEnable && aaEnable && aaSampleHigh && analogSLI && (chipNum != 2) && (vid2xMode == 0))) ||
((numChips == 4) && sliEnable && aaEnable && aaSampleHigh && !analogSLI && (chipNum == 2))) {
/* Handle four chips, 2-way analog SLI with digital 4-sample AA...*/
vsyncOffsetPixels = 7;
vsyncOffsetChars = 4;
vsyncOffsetHXtra = 0;
} else {
/* Run slave 8 clocks ahead */
vsyncOffsetPixels = 7;
vsyncOffsetChars = 5;
vsyncOffsetHXtra = 0;
}
temp = CFG_READ(chipNum, cfgSliAAMisc);
temp &= ~SST_VGA_VSYNC_OFFSET;
temp |= (vsyncOffsetPixels << SST_VGA_VSYNC_OFFSET_PIXELS_SHIFT) |
(vsyncOffsetChars << SST_VGA_VSYNC_OFFSET_CHARS_SHIFT) |
(vsyncOffsetHXtra << SST_VGA_VSYNC_OFFSET_HXTRA_SHIFT);
CFG_WRITE(chipNum, cfgSliAAMisc, temp);
}
/* Macros to save my effing fingers */
#define CFG_VIDEOCTRL0(flags, trueShift, falseShift) \
temp = (flags) | \
((trueShift) << SST_CFG_VIDEO_OTHERMUX_SEL_TRUE_SHIFT) | \
((falseShift) << SST_CFG_VIDEO_OTHERMUX_SEL_FALSE_SHIFT); \
CFG_WRITE(chipNum, cfgVideoCtrl0, temp);
#define CFG_VIDEOCTRL1(renderFetch, compareFetch, renderCRT, compareCRT) \
temp = ((renderFetch) << SST_CFG_SLI_RENDERMASK_FETCH_SHIFT) | \
((compareFetch) << SST_CFG_SLI_COMPAREMASK_FETCH_SHIFT) | \
((renderCRT) << SST_CFG_SLI_RENDERMASK_CRT_SHIFT) | \
((compareCRT) << SST_CFG_SLI_COMPAREMASK_CRT_SHIFT); \
CFG_WRITE(chipNum, cfgVideoCtrl1, temp);
#define CFG_VIDEOCTRL2(renderMask, compareMask) \
temp = ((renderMask) << SST_CFG_SLI_RENDERMASK_AAFIFO_SHIFT) | \
((compareMask) << SST_CFG_SLI_COMPAREMASK_AAFIFO_SHIFT); \
CFG_WRITE(chipNum, cfgVideoCtrl2, temp);
if(numChips == 1 && aaEnable) {
/* Single chip, 2-sample AA */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_2,
0,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE);
CFG_VIDEOCTRL1(0x00,
0x00,
0x00,
0x00);
CFG_VIDEOCTRL2(0x00, 0xff);
} else if(numChips == 2 && !sliEnable && aaEnable && aaSampleHigh && !analogSLI) {
/* Two chips, 4-sample digital AA... */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_4,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE_PLUS_AAFIFO,
0);
CFG_VIDEOCTRL1(0x00,
0x00,
0x00,
0x00);
CFG_VIDEOCTRL2(0x00, 0x00);
} else {
/* Second chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
0);
CFG_VIDEOCTRL1(0x00,
0x00,
0x00,
0xff);
CFG_VIDEOCTRL2(0x00, 0x00);
}
} else if(numChips == 2 && !sliEnable && aaEnable && aaSampleHigh && analogSLI) {
/* Two chips, 4-sample analog AA... */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_4,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
0);
} else {
/* Second chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_DAC_HSYNC_TRISTATE |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_4,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
0);
}
CFG_VIDEOCTRL1(0x00,
0x00,
0x00,
0x00);
CFG_VIDEOCTRL2(0x00, 0x00);
} else if(numChips == 2 && sliEnable && !aaEnable /*[dBorca]: && !aaSampleHigh*/ && !analogSLI) {
/* Two chips, 2-way digital SLI */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_AAFIFO,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE);
CFG_VIDEOCTRL1(0x01 << sliBandHeightLog2,
0x00,
0x00,
0x00);
CFG_VIDEOCTRL2(0x01 <<sliBandHeightLog2, 0x01 <<sliBandHeightLog2);
} else {
/* Second chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
/*[dBorca]: SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |*/
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE);
CFG_VIDEOCTRL1((numChips - 1) << sliBandHeightLog2,
chipNum << sliBandHeightLog2,
0x00,
0xff);
CFG_VIDEOCTRL2((numChips - 1) << sliBandHeightLog2, chipNum << sliBandHeightLog2);
}
} else if((numChips == 2 || numChips == 4) && sliEnable && !aaEnable /*[dBorca]: && !aaSampleHigh*/ && analogSLI) {
/* 2 or 4 chips, 2/4-way analog SLI */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE);
CFG_VIDEOCTRL1((numChips - 1) << sliBandHeightLog2,
0x00,
(numChips - 1) << sliBandHeightLog2,
0x00);
CFG_VIDEOCTRL2(0x00, 0xff);
} else {
/* Remaining chips */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE);
CFG_VIDEOCTRL1((numChips - 1) << sliBandHeightLog2,
chipNum << sliBandHeightLog2,
(numChips - 1) << sliBandHeightLog2,
chipNum << sliBandHeightLog2);
CFG_VIDEOCTRL2(0x00, 0xff);
}
} else if(numChips == 2 && sliEnable && aaEnable && !aaSampleHigh && !analogSLI) {
/* Two chips, 2-sample AA with 2-way digital SLI... */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_2,
SST_CFG_VIDEO_OTHERMUX_SEL_AAFIFO,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE);
CFG_VIDEOCTRL1(0x01 << sliBandHeightLog2,
0x00,
0x00,
0x00);
CFG_VIDEOCTRL2(0x01 << sliBandHeightLog2, 0x01 << sliBandHeightLog2);
} else {
/* Second chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE);
CFG_VIDEOCTRL1((numChips - 1) << sliBandHeightLog2,
chipNum << sliBandHeightLog2,
0x00,
0xff);
CFG_VIDEOCTRL2((numChips - 1) << sliBandHeightLog2, chipNum << sliBandHeightLog2);
}
} else if(numChips == 2 && sliEnable && aaEnable && !aaSampleHigh && analogSLI) {
/* Two chips, 2-sample AA with 2-way analog SLI... */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_2,
0,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE);
CFG_VIDEOCTRL1(0x01 << sliBandHeightLog2,
0x00,
0x01 << sliBandHeightLog2,
0x00);
CFG_VIDEOCTRL2(0x00, 0xff);
} else {
/* Second chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_2,
0,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE);
CFG_VIDEOCTRL1((numChips - 1) << sliBandHeightLog2,
chipNum << sliBandHeightLog2,
(numChips - 1) << sliBandHeightLog2,
chipNum << sliBandHeightLog2);
CFG_VIDEOCTRL2(0x00, 0xff);
}
} else if(numChips == 4 && sliEnable && aaEnable && !aaSampleHigh && analogSLI) {
/* Four chip, 2-sample AA. two units of 2 chip analog SLI, with 1 subsample per unit. */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_DIVIDE_VIDEO_BY_2,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE_PLUS_AAFIFO,
0);
CFG_VIDEOCTRL1(0x01 << sliBandHeightLog2,
0x00 << sliBandHeightLog2,
0x01 << sliBandHeightLog2,
0x00 << sliBandHeightLog2);
CFG_VIDEOCTRL2(0x00, 0x00);
} else if(chipNum == 1 || chipNum == 3) {
/* Second and fourth chips */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_DAC_HSYNC_TRISTATE |
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
0);
CFG_VIDEOCTRL1(0x01 << sliBandHeightLog2,
(chipNum >> 1) << sliBandHeightLog2,
0x00 << sliBandHeightLog2,
0xFF << sliBandHeightLog2);
CFG_VIDEOCTRL2(0x00, 0x00);
} else {
/* Third chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_DIVIDE_VIDEO_BY_2,
0,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE_PLUS_AAFIFO);
CFG_VIDEOCTRL1(0x01 << sliBandHeightLog2,
0x01 << sliBandHeightLog2,
0x01 << sliBandHeightLog2,
0x01 << sliBandHeightLog2);
CFG_VIDEOCTRL2(0x00, 0xff);
}
} else if(numChips == 4 && sliEnable && aaEnable && aaSampleHigh == 1 && analogSLI) {
/* Four chip, 4-sample AA. 1 subsample per chip analog SLI'ed */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_DIVIDE_VIDEO_BY_4,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE_PLUS_AAFIFO,
0);
CFG_VIDEOCTRL1(0x00,
0x00,
0x00,
0x00);
if(vid2xMode) {
CFG_VIDEOCTRL2(0x00, 0xff);
} else {
CFG_VIDEOCTRL2(0x00, 0x00);
}
} else if(chipNum == 1 || chipNum == 3) {
/* Second and fourth chips */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_DAC_HSYNC_TRISTATE |
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
0);
CFG_VIDEOCTRL1(0x00,
0x00,
0x00,
0xff);
if(vid2xMode) {
CFG_VIDEOCTRL2(0x00, 0xff);
} else {
CFG_VIDEOCTRL2(0x00, 0x00);
}
} else {
/* Third chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_DAC_HSYNC_TRISTATE |
SST_CFG_DIVIDE_VIDEO_BY_4,
0,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE_PLUS_AAFIFO);
CFG_VIDEOCTRL1(0x00,
0x00,
0x00,
0x00);
CFG_VIDEOCTRL2(0x00, 0xff);
}
} else if(numChips == 4 && !sliEnable && aaEnable && aaSampleHigh == 2 && analogSLI) {
/* Four chip, 8-sample AA. 2 subsample per chip analog SLI'ed */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_8,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE_PLUS_AAFIFO,
0);
CFG_VIDEOCTRL1(0x00,
0x00,
0x00,
0x00);
if(vid2xMode) {
CFG_VIDEOCTRL2(0x00, 0xff);
} else {
CFG_VIDEOCTRL2(0x00, 0x00);
}
} else if(chipNum == 1 || chipNum == 3) {
/* Second and fourth chips */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DAC_HSYNC_TRISTATE |
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
0);
CFG_VIDEOCTRL1(0x00,
0x00,
0x00,
0xff);
if(vid2xMode) {
CFG_VIDEOCTRL2(0x00, 0xff);
} else {
CFG_VIDEOCTRL2(0x00, 0x00);
}
} else {
/* Third chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DAC_HSYNC_TRISTATE |
SST_CFG_DIVIDE_VIDEO_BY_8,
0,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE_PLUS_AAFIFO);
CFG_VIDEOCTRL1(0x00,
0x00,
0x00,
0x00);
CFG_VIDEOCTRL2(0x00, 0xff);
}
} else if(numChips == 2 && !sliEnable && aaEnable && !aaSampleHigh && !analogSLI) {
/* Two chips, 2-sample AA. 1 subsample per chip digital SLI'ed */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_DIVIDE_VIDEO_BY_2,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE_PLUS_AAFIFO,
0);
CFG_VIDEOCTRL1(0x00,
0x00,
0x00,
0x00);
CFG_VIDEOCTRL2(0x00, 0x00);
} else {
/* Second chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
0);
CFG_VIDEOCTRL1(0x00,
0x00,
0x00,
0xff);
CFG_VIDEOCTRL2(0x00, 0x00);
}
} else if(numChips == 2 && !sliEnable && aaEnable && !aaSampleHigh && analogSLI) {
/* Two chips, 2-sample AA. 1 subsample per chip analog SLI'ed */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_DIVIDE_VIDEO_BY_2,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
0);
} else {
/* Second chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_DAC_HSYNC_TRISTATE |
SST_CFG_DIVIDE_VIDEO_BY_2,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
0);
}
CFG_VIDEOCTRL1(0x00,
0x00,
0x00,
0x00);
CFG_VIDEOCTRL2(0x00, 0x00);
} else if(numChips == 4 && sliEnable && !aaEnable && !analogSLI) {
/* Four chips, 4-way digital SLI... */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_SLI_AAFIFO_COMPARE_INV |
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_AAFIFO,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE);
CFG_VIDEOCTRL1((numChips - 1) << sliBandHeightLog2,
0x00,
0x00,
0x00);
CFG_VIDEOCTRL2((numChips - 1) << sliBandHeightLog2, 0x00 << sliBandHeightLog2);
} else {
/* Remaining chips */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE);
CFG_VIDEOCTRL1((numChips - 1) << sliBandHeightLog2,
chipNum << sliBandHeightLog2,
0x00,
0xff);
CFG_VIDEOCTRL2((numChips - 1) << sliBandHeightLog2, chipNum << sliBandHeightLog2);
}
} else if(numChips == 4 && sliEnable && aaEnable && !aaSampleHigh && !analogSLI) {
/* Four chips, 2-sample AA with 4-way digital SLI */
if(chipNum == 0) {
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_SLI_AAFIFO_COMPARE_INV |
SST_CFG_DIVIDE_VIDEO_BY_2,
SST_CFG_VIDEO_OTHERMUX_SEL_AAFIFO,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE);
CFG_VIDEOCTRL1((numChips - 1) << sliBandHeightLog2,
0x00,
0x00,
0x00);
CFG_VIDEOCTRL2((numChips - 1) << sliBandHeightLog2,
0x00);
} else {
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE);
CFG_VIDEOCTRL1((numChips - 1) << sliBandHeightLog2,
chipNum << sliBandHeightLog2,
0x00,
0xff);
CFG_VIDEOCTRL2((numChips - 1) << sliBandHeightLog2,
chipNum << sliBandHeightLog2);
}
} else if(numChips == 4 && sliEnable && aaEnable && aaSampleHigh == 1 && !analogSLI) {
/* Four chip, 2-way analog SLI with digital 4-sample AA */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_4,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE_PLUS_AAFIFO,
0);
CFG_VIDEOCTRL1(0x01 << sliBandHeightLog2,
0x00 << sliBandHeightLog2,
0x01 << sliBandHeightLog2,
0x00 << sliBandHeightLog2);
CFG_VIDEOCTRL2(0x00, 0x00);
} else if(chipNum == 1 || chipNum == 3) {
/* Second and fourth chips */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_DAC_HSYNC_TRISTATE |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_1,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
0);
CFG_VIDEOCTRL1(0x01 << sliBandHeightLog2,
(chipNum >> 1) << sliBandHeightLog2,
0x00 << sliBandHeightLog2,
0xFF << sliBandHeightLog2);
CFG_VIDEOCTRL2(0x00, 0x00);
} else {
/* Third chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_4,
0,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE_PLUS_AAFIFO);
CFG_VIDEOCTRL1(0x01 << sliBandHeightLog2,
0x01 << sliBandHeightLog2,
0x01 << sliBandHeightLog2,
0x01 << sliBandHeightLog2);
CFG_VIDEOCTRL2(0x00, 0xff);
}
} else if(numChips == 4 && sliEnable && aaEnable && aaSampleHigh == 1 && analogSLI) {
/* Four chip, 2-way analog SLI with analog 4-sample AA */
if(chipNum == 0) {
/* First chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_4,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
0);
CFG_VIDEOCTRL1(0x01 << sliBandHeightLog2,
0x00 << sliBandHeightLog2,
0x01 << sliBandHeightLog2,
0x00 << sliBandHeightLog2);
CFG_VIDEOCTRL2(0x00, 0x00);
} else if(chipNum == 1 || chipNum == 3) {
/* Second and fourth chips */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_DAC_HSYNC_TRISTATE |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_4,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
0);
CFG_VIDEOCTRL1(0x01 << sliBandHeightLog2,
(chipNum >> 1) << sliBandHeightLog2,
0x01 << sliBandHeightLog2,
(chipNum >> 1) << sliBandHeightLog2);
CFG_VIDEOCTRL2(0x00, 0x00);
} else {
/* Third chip */
CFG_VIDEOCTRL0(SST_CFG_ENHANCED_VIDEO_EN |
SST_CFG_ENHANCED_VIDEO_SLV |
SST_CFG_VIDEO_LOCALMUX_DESKTOP_PLUS_OVERLAY |
SST_CFG_DIVIDE_VIDEO_BY_4,
SST_CFG_VIDEO_OTHERMUX_SEL_PIPE,
0);
CFG_VIDEOCTRL1(0x01 << sliBandHeightLog2,
0x01 << sliBandHeightLog2,
0x01 << sliBandHeightLog2,
0x01 << sliBandHeightLog2);
CFG_VIDEOCTRL2(0x00, 0x00);
}
}
/* Make sure that last chip properly waits for data to be xfered
* over the PCI bus before driving... */
if((numChips == 4 && sliEnable && aaEnable && aaSampleHigh && chipNum == 3) ||
(numChips == 4 && sliEnable && aaEnable && !aaSampleHigh && analogSLI && chipNum == 3)) {
temp = CFG_READ(chipNum, cfgSliAAMisc);
temp |= SST_CFG_AA_LFB_RD_SLV_WAIT;
CFG_WRITE(chipNum, cfgSliAAMisc, temp);
}
/* Deal with the problem for LFB reads where the data really needs to
come from 4 different chips. Since the hardware does not support
this, we figure out a way to only return aliased data back back...
This is accomplished by having the Master return its lfb data
By turning off AA LFB reads, chips 2/3 no longer snoop lfb reads
at all. Then, there is only handshaking between chips 0 & 1 so
the Master stays happy.
*/
if(numChips == 4 && !sliEnable && aaEnable && aaSampleHigh && analogSLI && chipNum > 1) {
temp = CFG_READ(chipNum, cfgAALfbCtrl);
temp &= ~SST_AA_LFB_READ_ENABLE;
CFG_WRITE(chipNum, cfgAALfbCtrl, temp);
}
if(chipNum > 0) {
/* For the slave chips, make the video PLL lock to the Master's
* sync_clk_out clock output... */
temp = CFG_READ(chipNum, cfgVideoCtrl0);
temp |= SST_CFG_VIDPLL_SEL;
CFG_WRITE(chipNum, cfgVideoCtrl0, temp);
/* Power down slave(s) RAMDAC */
HWC_IO_LOAD_SLAVE(chipNum, bInfo->regInfo, miscInit1, temp);
temp |= SST_POWERDOWN_DAC;
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, miscInit1, temp);
}
else if (numChips == 4) /* chipNum==0 */
{
/* Special Case 4 way where master also needs to sync from slave */
temp = CFG_READ(chipNum, cfgVideoCtrl0);
temp |= SST_CFG_VIDPLL_SEL;
CFG_WRITE(chipNum, cfgVideoCtrl0, temp);
}
LOG((dbg,"cfgInitEnable: %08lx\n",CFG_READ(chipNum, cfgInitEnable_FabID)));
LOG((dbg,"cfgPciDecode: %08lx\n",CFG_READ(chipNum, cfgPciDecode)));
LOG((dbg,"cfgVideoCtrl0: %08lx\n",CFG_READ(chipNum, cfgVideoCtrl0)));
LOG((dbg,"cfgVideoCtrl1: %08lx\n",CFG_READ(chipNum, cfgVideoCtrl1)));
LOG((dbg,"cfgVideoCtrl2: %08lx\n",CFG_READ(chipNum, cfgVideoCtrl2)));
LOG((dbg,"cfgSliLfbCtrl: %08lx\n",CFG_READ(chipNum, cfgSliLfbCtrl)));
LOG((dbg,"cfgAADepthAp: %08lx\n",CFG_READ(chipNum, cfgAADepthBufferAperture)));
LOG((dbg,"cfgAALfbCtrl: %08lx\n",CFG_READ(chipNum, cfgAALfbCtrl)));
LOG((dbg,"cfgSliAAMisc: %08lx\n",CFG_READ(chipNum, cfgSliAAMisc)));
}
} else { /* Disable AA and/or SLI */
for(chipNum = 0; chipNum < numChips; chipNum++) {
temp = CFG_READ(chipNum, cfgInitEnable_FabID) >> 8;
temp &= ~(SST_ADDRESS_SNOOP_ENABLE | SST_MEMBASE0_SNOOP_ENABLE | SST_MEMBASE1_SNOOP_ENABLE | SST_ADDRESS_SNOOP_SLAVE |
SST_INIT_REGISTER_SNOOP_ENABLE | SST_MEMBASE0_SNOOP | SST_QUICK_SAMPLING | SST_SWAP_MASTER | SST_SWAPBUFFER_ALGORITHM);
CFG_WRITE(chipNum, cfgInitEnable_FabID, temp << 8);
CFG_WRITE(chipNum, cfgSliLfbCtrl, 0);
CFG_WRITE(chipNum, cfgAALfbCtrl, 0);
CFG_WRITE(chipNum, cfgSliAAMisc, 0);
// Make sure slave chips don't drive HSYNC & VSYNC
if(chipNum > 0) {
CFG_WRITE(chipNum, cfgVideoCtrl0, SST_CFG_DAC_HSYNC_TRISTATE | SST_CFG_DAC_VSYNC_TRISTATE);
} else {
CFG_WRITE(chipNum, cfgVideoCtrl0, 0);
}
CFG_WRITE(chipNum, cfgVideoCtrl1, 0);
CFG_WRITE(chipNum, cfgVideoCtrl2, 0);
CFG_WRITE(chipNum, cfgAADepthBufferAperture, 0);
/* Kill the DAC & video output on the slaves */
if(chipNum > 0) {
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, dacMode, SST_DAC_DPMS_ON_VSYNC | SST_DAC_DPMS_ON_HSYNC);
HWC_IO_LOAD_SLAVE(chipNum, bInfo->regInfo, vidProcCfg, temp);
temp &= ~SST_VIDEO_PROCESSOR_EN;
HWC_IO_STORE_SLAVE(chipNum, bInfo->regInfo, vidProcCfg, temp);
}
}
}
}