mirror of
https://github.com/X11Libre/xf86-video-voodoo.git
synced 2026-03-24 01:25:25 +00:00
813 lines
18 KiB
C
813 lines
18 KiB
C
/*
|
|
* Portions derived from linux/drivers/video/sstfb.c
|
|
* -- voodoo graphics frame buffer
|
|
* Copyright (c) 2000-2002 Ghozlane Toumi <gtoumi@laposte.net>
|
|
*
|
|
* Relicensed from GPL to the X license by consent of the author
|
|
*
|
|
* Other code Alan Cox (c) Copyright 2004 Red Hat Inc.
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that
|
|
* copyright notice and this permission notice appear in supporting
|
|
* documentation, and that the names of Red Hat, Alan Cox and Ghozlane Toumi
|
|
* not be used in advertising or publicity pertaining to distribution of the
|
|
* software without specific, written prior permission. Th authors make no
|
|
* representations about the suitability of this software for any purpose.
|
|
* It is provided "as is" without express or implied warranty.
|
|
*
|
|
* THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL RICHARD HECKER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* THIS SOFTWARE IS NOT DESIGNED FOR USE IN SAFETY CRITICAL SYSTEMS OF
|
|
* ANY KIND OR FORM.
|
|
*
|
|
* Freely reviewably music for this hacking supplied by
|
|
* http://www.hoerstreich.de
|
|
* http://www.machinaesupremacy.com
|
|
* http://www.magnatune.com
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "fb.h"
|
|
#include "micmap.h"
|
|
#include "xf86.h"
|
|
#include "xf86_OSproc.h"
|
|
#include "xf86Pci.h"
|
|
#include "xf86cmap.h"
|
|
#include "shadowfb.h"
|
|
#include "vgaHW.h"
|
|
#include "compiler.h"
|
|
|
|
#include "voodoo.h"
|
|
|
|
#include <X11/extensions/xf86dgaproto.h>
|
|
|
|
#ifdef HAVE_XEXTPROTO_71
|
|
#include <X11/extensions/dpmsconst.h>
|
|
#else
|
|
#define DPMS_SERVER
|
|
#include <X11/extensions/dpms.h>
|
|
#endif
|
|
|
|
#include "mipict.h"
|
|
#include "dixstruct.h"
|
|
|
|
#include <unistd.h>
|
|
|
|
/*
|
|
* Big endian might need to byteswap these ?
|
|
*/
|
|
|
|
/*
|
|
* Write to chuck and bruce
|
|
*/
|
|
|
|
static CARD32 mmio32_r(VoodooPtr pVoo, int reg)
|
|
{
|
|
volatile CARD32 *ptr = (CARD32 *)(pVoo->MMIO + reg);
|
|
CARD32 val = *ptr;
|
|
return val;
|
|
}
|
|
|
|
static void mmio32_w(VoodooPtr pVoo, int reg, CARD32 val)
|
|
{
|
|
volatile CARD32 *ptr = (CARD32 *)(pVoo->MMIO + reg);
|
|
*ptr = val;
|
|
}
|
|
|
|
/*
|
|
* Write to chuck only
|
|
*/
|
|
|
|
static void mmio32_w_chuck(VoodooPtr pVoo, int reg, CARD32 val)
|
|
{
|
|
volatile CARD32 *ptr = (CARD32 *)(pVoo->MMIO + (reg |(1<<10)));
|
|
*ptr = val;
|
|
}
|
|
|
|
/*
|
|
* Size the video RAM. Texture ram sizing is different and separate
|
|
* but we don't use the texture ram for 2D anyway.
|
|
*/
|
|
|
|
int VoodooMemorySize(VoodooPtr pVoo)
|
|
{
|
|
volatile CARD32 *fp = (volatile CARD32 *)pVoo->FBBase;
|
|
fp[0] = 0xA5A5A5A5;
|
|
fp[1<<18] = 0xA5A5A5A5;
|
|
fp[1<<19] = 0xA5A5A5A5;
|
|
|
|
fp[0] = 0x5A5A5A5A;
|
|
|
|
if(fp[1<<19] == 0xA5A5A5A5)
|
|
return 4; /* 4Mb Card */
|
|
if(fp[1<<18] == 0xA5A5A5A5)
|
|
return 2; /* 2Mb Card */
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* FIXME: If we are also doing 3D or DRI paths do we need
|
|
* to fix this path to issue a NOP command as per the chip errata?
|
|
*/
|
|
|
|
static void wait_idle(VoodooPtr pVoo)
|
|
{
|
|
int i = 0;
|
|
|
|
while(i < 5)
|
|
{
|
|
if((mmio32_r(pVoo,0) & 0x80) == 0)
|
|
i++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* PCI control registers
|
|
*/
|
|
|
|
/*
|
|
* PCI enables. Used for setup, mode switch etc
|
|
*/
|
|
|
|
static void pci_enable(VoodooPtr pVoo, int wr, int dac, int fifo)
|
|
{
|
|
CARD32 x;
|
|
PCI_READ_LONG(pVoo->PciInfo, &x, 0x40);
|
|
x &= ~7;
|
|
x |= wr;
|
|
x |= fifo<<1;
|
|
x |= dac<<2;
|
|
PCI_WRITE_LONG(pVoo->PciInfo, x, 0x40);
|
|
}
|
|
|
|
/*
|
|
* VClock control
|
|
*/
|
|
|
|
static void vclock_enable(VoodooPtr pVoo, int enable)
|
|
{
|
|
if(enable)
|
|
PCI_WRITE_LONG(pVoo->PciInfo, 0, 0xc0);
|
|
else
|
|
PCI_WRITE_LONG(pVoo->PciInfo, 0, 0xe0);
|
|
}
|
|
|
|
/*
|
|
* DPMS
|
|
*/
|
|
|
|
void VoodooBlank(VoodooPtr pVoo)
|
|
{
|
|
vclock_enable(pVoo, 0);
|
|
pci_enable(pVoo, 1, 0, 0);
|
|
|
|
mmio32_w(pVoo, 0x214, mmio32_r(pVoo, 0x214) | 0x100);
|
|
wait_idle(pVoo);
|
|
|
|
mmio32_w(pVoo, 0x210, mmio32_r(pVoo, 0x210) | 6);
|
|
wait_idle(pVoo);
|
|
|
|
mmio32_w(pVoo, 0x218, mmio32_r(pVoo, 0x218) & ~(1<<22));
|
|
wait_idle(pVoo);
|
|
}
|
|
|
|
/*
|
|
* Read and write the DAC registers
|
|
*/
|
|
|
|
static void dac_out(VoodooPtr pVoo, CARD32 reg, CARD32 val)
|
|
{
|
|
mmio32_w(pVoo, 0x22C, (reg << 8) | val);
|
|
wait_idle(pVoo);
|
|
}
|
|
|
|
static CARD32 dac_in(VoodooPtr pVoo, CARD32 reg)
|
|
{
|
|
CARD32 r;
|
|
mmio32_w(pVoo, 0x22C, (1<<11)|(reg<< 8));
|
|
wait_idle(pVoo);
|
|
r = mmio32_r(pVoo, 0x218) & 0xFF;
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Indexed (or should that be "demented") mode on the TI
|
|
* and AT&T DAC's
|
|
*/
|
|
|
|
static void dac_out_idx(VoodooPtr pVoo, CARD32 reg, CARD32 val)
|
|
{
|
|
dac_out(pVoo, 0, reg);
|
|
dac_out(pVoo, 2, val);
|
|
}
|
|
|
|
static CARD32 dac_in_idx(VoodooPtr pVoo, CARD32 reg)
|
|
{
|
|
dac_out(pVoo, 0, reg);
|
|
return dac_in(pVoo, 2);
|
|
}
|
|
|
|
/*
|
|
* We have generic ics5432 code we perhaps ought to use instead.
|
|
* This is based on the sstfb and Glide logic.
|
|
*/
|
|
|
|
#define ICS_PLL_CLK0_1_INI 0x55 /* Frequencies for detecting ICS */
|
|
#define ICS_PLL_CLK0_7_INI 0x71
|
|
#define ICS_PLL_CLK1_B_INI 0x79
|
|
|
|
static int probe_ics5432(VoodooPtr pVoo)
|
|
{
|
|
int i;
|
|
CARD32 m01, m07, m11;
|
|
|
|
for(i = 0; i < 5; i++)
|
|
{
|
|
dac_out(pVoo, 7, 1);
|
|
m01 = dac_in(pVoo,5);
|
|
dac_in(pVoo,5);
|
|
dac_out(pVoo,7, 7);
|
|
m07 = dac_in(pVoo, 5);
|
|
dac_in(pVoo,5);
|
|
dac_out(pVoo,7, 11);
|
|
m11 = dac_in(pVoo, 5);
|
|
dac_in(pVoo, 5);
|
|
|
|
if(m01 == ICS_PLL_CLK0_1_INI &&
|
|
m07 == ICS_PLL_CLK0_7_INI &&
|
|
m11 == ICS_PLL_CLK1_B_INI)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Activate backdoor on DACs
|
|
*/
|
|
|
|
static void dacdoor(VoodooPtr pVoo)
|
|
{
|
|
dac_out(pVoo,0, 0);
|
|
dac_in(pVoo,2);
|
|
dac_in(pVoo,2);
|
|
dac_in(pVoo,2);
|
|
dac_in(pVoo,2);
|
|
}
|
|
|
|
/*
|
|
* Set a PLL on the DAC. Either vClock (0) or gClock (1)
|
|
*/
|
|
|
|
static void voodoo_set_pll(VoodooPtr pVoo, int pllnum)
|
|
{
|
|
CARD32 cr0;
|
|
if(pVoo->DAC == DAC_ID_ATT || pVoo->DAC == DAC_ID_TI)
|
|
{
|
|
CARD32 cc;
|
|
dacdoor(pVoo);
|
|
cr0 = dac_in(pVoo, 2);
|
|
|
|
dacdoor(pVoo);
|
|
dac_out(pVoo, 2, (cr0 & 0xF0) | 0xB); /* Switch to index mode */
|
|
|
|
/* Sleep a bit */
|
|
usleep(300);
|
|
|
|
cc = dac_in_idx(pVoo, 6);
|
|
if(pllnum == 0)
|
|
{
|
|
dac_out_idx(pVoo, 0x48, pVoo->vClock.m);
|
|
dac_out_idx(pVoo, 0x49, (pVoo->vClock.p << 6) | pVoo->vClock.n);
|
|
dac_out_idx(pVoo, 6, (cc & 0x0F) | 0xA0 );
|
|
}
|
|
else
|
|
{
|
|
dac_out_idx(pVoo, 0x6C, pVoo->gClock.m);
|
|
dac_out_idx(pVoo, 0x6D, (pVoo->gClock.p << 6) | pVoo->vClock.n);
|
|
dac_out_idx(pVoo, 6, (cc & 0x0F) | 0x0B);
|
|
}
|
|
return;
|
|
}
|
|
/* ICS5432 */
|
|
dac_out(pVoo, 7, 14);
|
|
cr0 = dac_in(pVoo, 5);
|
|
if(pllnum == 0)
|
|
{
|
|
dac_out(pVoo, 4, 0);
|
|
dac_out(pVoo, 5, pVoo->vClock.m);
|
|
dac_out(pVoo, 5, pVoo->vClock.p << 5 | pVoo->vClock.n);
|
|
dac_out(pVoo, 4, 14);
|
|
dac_out(pVoo, 5, (cr0 & 0xD8) | (1<<5));
|
|
}
|
|
else
|
|
{
|
|
dac_out(pVoo, 4, 10);
|
|
dac_out(pVoo, 5, pVoo->gClock.m);
|
|
dac_out(pVoo, 5, pVoo->gClock.p << 5 | pVoo->gClock.n);
|
|
dac_out(pVoo, 4, 14);
|
|
dac_out(pVoo, 5, (cr0 & 0xEF));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set the depth in the DAC. This must match the frame
|
|
* buffer format. Right now we could hard code 16, in fact
|
|
* it may be correct to always do so.. ?
|
|
*/
|
|
|
|
static void voodoo_set_depth(VoodooPtr pVoo, int depth)
|
|
{
|
|
CARD32 cr0;
|
|
|
|
if(pVoo->DAC == DAC_ID_ATT || pVoo->DAC == DAC_ID_TI)
|
|
{
|
|
dacdoor(pVoo);
|
|
cr0 = dac_in(pVoo, 2);
|
|
|
|
dacdoor(pVoo);
|
|
|
|
if(depth == 16)
|
|
dac_out(pVoo, 2, (cr0 & 0x0F) | 0x50);
|
|
else if(depth ==24 || depth == 32)
|
|
dac_out(pVoo, 2, (cr0 & 0x0F) | 0x70);
|
|
}
|
|
else if(pVoo->DAC == DAC_ID_ICS)
|
|
{
|
|
if(depth == 16)
|
|
dac_out(pVoo, 6, 0x50);
|
|
else
|
|
dac_out(pVoo, 6, 0x70);
|
|
}
|
|
}
|
|
|
|
static int voodoo_find_dac(VoodooPtr pVoo)
|
|
{
|
|
CARD32 vendor_id, device_id;
|
|
|
|
#define DAC_VENDOR_ATT 0x84
|
|
#define DAC_DEVICE_ATT20C409 0x09
|
|
#define DAC_VENDOR_TI 0x97
|
|
#define DAC_DEVICE_TITVP3409 0x09
|
|
|
|
dacdoor(pVoo);
|
|
dac_in(pVoo, 2);
|
|
vendor_id = dac_in(pVoo, 2);
|
|
device_id = dac_in(pVoo, 2);
|
|
|
|
/* AT&T 20C409 and clones */
|
|
if(vendor_id == DAC_VENDOR_ATT && device_id == DAC_DEVICE_ATT20C409)
|
|
return DAC_ID_ATT;
|
|
|
|
if(vendor_id == DAC_VENDOR_TI && device_id == DAC_DEVICE_TITVP3409)
|
|
return DAC_ID_TI;
|
|
|
|
/* ICS5432 doesn't implement the back door. Glide does some
|
|
quick tests to see if it is an ICS5432 just in case. */
|
|
|
|
if(probe_ics5432(pVoo))
|
|
return DAC_ID_ICS;
|
|
|
|
/* Shouldn't be any boards that get this far */
|
|
ErrorF("Voodoo card with unknown DAC. Not supported.\n");
|
|
return DAC_UNKNOWN;
|
|
}
|
|
|
|
/*
|
|
* Compute the PLL clock values. This is directly based on the
|
|
* technique used by sstfb.
|
|
*/
|
|
|
|
/* compute the m,n,p , returns the real freq
|
|
* (ics datasheet : N <-> N1 , P <-> N2)
|
|
*
|
|
* Fout= Fref * (M+2)/( 2^P * (N+2))
|
|
* we try to get close to the asked freq
|
|
* with P as high, and M as low as possible
|
|
* range:
|
|
* ti/att : 0 <= M <= 255; 0 <= P <= 3; 0<= N <= 63
|
|
* ics : 1 <= M <= 127; 0 <= P <= 3; 1<= N <= 31
|
|
*
|
|
* We will use the lowest limitation, should be precise enough
|
|
*/
|
|
|
|
static int iabs(int a)
|
|
{
|
|
if(a >= 0)
|
|
return a;
|
|
return -a;
|
|
}
|
|
|
|
static int sst_calc_pll(const int freq, PLLClock *t)
|
|
{
|
|
int m, m2, n, p, best_err, fout;
|
|
int best_n=-1;
|
|
int best_m=-1;
|
|
|
|
best_err = freq;
|
|
p=3;
|
|
/* f * 2^P = vco should be less than VCOmax ~ 250 MHz for ics */
|
|
while (((1 << p) * freq > 260000) && (p >= 0))
|
|
p--;
|
|
if (p == -1)
|
|
return 0;
|
|
for (n = 1; n < 32; n++) {
|
|
/* Calc 2 * m so we can round it later */
|
|
m2 = (2 * freq * (1 << p) * (n + 2) ) / 14318 - 4 ;
|
|
|
|
m = (m2 % 2) ? m2/2+1 : m2/2 ;
|
|
if (m >= 128)
|
|
break;
|
|
fout = (14318 * (m + 2)) / ((1 << p) * (n + 2));
|
|
if (iabs(fout - freq) < best_err && m > 0) {
|
|
best_n = n;
|
|
best_m = m;
|
|
best_err = iabs(fout - freq);
|
|
/* We get the lowest m , allowing 0.5% error in freq */
|
|
if (200*best_err < freq)
|
|
break;
|
|
}
|
|
}
|
|
if (best_n == -1) /* Unlikely, but who knows ? */
|
|
return 0;
|
|
t->p=p;
|
|
t->n=best_n;
|
|
t->m=best_m;
|
|
return (14318 * (t->m + 2)) / ((1 << t->p) * (t->n + 2));
|
|
}
|
|
|
|
|
|
/*
|
|
* Here endeth the DAC code
|
|
*/
|
|
|
|
|
|
/*
|
|
* Higher level mode management
|
|
*/
|
|
|
|
static void voodoo_set_mode(VoodooPtr pVoo, DisplayModePtr mode)
|
|
{
|
|
CARD32 hbporch = mode->CrtcHTotal - mode->CrtcHSyncEnd;
|
|
CARD32 vbporch = mode->CrtcVTotal - mode->CrtcVSyncEnd;
|
|
CARD32 hsyncstart = mode->CrtcHSyncEnd - mode->CrtcHSyncStart;
|
|
CARD32 hsyncend = mode->CrtcHTotal - hsyncstart;
|
|
CARD32 vsyncstart = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
|
|
CARD32 vsyncend = mode->CrtcVTotal - vsyncstart;
|
|
CARD32 width = mode->CrtcHDisplay;
|
|
CARD32 height = mode->CrtcVDisplay;
|
|
|
|
/* Even numbers of lines for interlace */
|
|
if((mode->Flags & V_INTERLACE) && (vbporch & 1))
|
|
vbporch += 1;
|
|
/* Doublescan does what you expect */
|
|
if(mode->Flags & V_DBLSCAN)
|
|
{
|
|
/* Not sure if we need to do all of these */
|
|
vbporch <<= 1;
|
|
hbporch <<= 1;
|
|
hsyncend <<= 1;
|
|
hsyncstart <<= 1;
|
|
vsyncend <<= 1;
|
|
vsyncstart <<= 1;
|
|
width <<= 1;
|
|
height <<= 1;
|
|
}
|
|
|
|
/* Write back porch values */
|
|
mmio32_w(pVoo, 0x208, (vbporch << 16) | (hbporch - 2));
|
|
/* Write displayed area */
|
|
mmio32_w(pVoo, 0x20C, (height << 16) | (width - 1));
|
|
mmio32_w(pVoo, 0x220, (hsyncend - 1 ) << 16 | (hsyncstart - 1));
|
|
mmio32_w(pVoo, 0x224, (vsyncend << 16) | vsyncstart);
|
|
}
|
|
|
|
/*
|
|
* Set up a Voodoo video mode. Note that we do need to have
|
|
* save/restore functions here too because the user might be
|
|
* using sstfb... Eventually..
|
|
*/
|
|
|
|
int VoodooMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
|
|
{
|
|
CARD32 f1, f2, f3;
|
|
VoodooPtr pVoo = VoodooPTR(pScrn);
|
|
int tiles;
|
|
|
|
/* FIXME: Compute PLL and check */
|
|
|
|
sst_calc_pll(mode->SynthClock, &pVoo->vClock);
|
|
|
|
mmio32_w(pVoo, 0x120, 0); /* NOP */
|
|
wait_idle(pVoo);
|
|
pci_enable(pVoo, 1, 0, 0);
|
|
mmio32_w(pVoo, 0x214, mmio32_r(pVoo,0x214)|(1<<8));
|
|
mmio32_w(pVoo, 0x210, mmio32_r(pVoo,0x210)|6);
|
|
mmio32_w(pVoo, 0x218, mmio32_r(pVoo,0x218) & ~(1<<22));
|
|
wait_idle(pVoo);
|
|
|
|
voodoo_set_mode(pVoo, mode);
|
|
|
|
f2 = mmio32_r(pVoo,0x218);
|
|
f3 = mmio32_r(pVoo,0x21c);
|
|
|
|
pci_enable(pVoo, 1, 1, 0);
|
|
|
|
voodoo_set_depth(pVoo, 16); /* Hardware output is always 16bpp */
|
|
voodoo_set_pll(pVoo, 0);
|
|
|
|
pci_enable(pVoo, 1, 0, 0);
|
|
|
|
mmio32_w(pVoo, 0x218, f2);
|
|
mmio32_w(pVoo, 0x21C, f3);
|
|
|
|
f1 = mmio32_r(pVoo,0x214);
|
|
|
|
f1 &= 0x8080010F; /* Mask off video bits */
|
|
f1 |= 0x21E000; /* Enable blanking, data, vsync, dclock 2x sel */
|
|
|
|
/* Number of 64 pixel tiles */
|
|
tiles = (mode->CrtcHDisplay + 63) / 64;
|
|
|
|
if(pVoo->Voodoo2)
|
|
f1|= ((tiles & 0x10) ? 1<<24 : 0) | (tiles & 0x0f) << 4;
|
|
else
|
|
f1|= tiles << 4;
|
|
|
|
pVoo->Tiles = tiles * 2;
|
|
pVoo->Width = mode->CrtcHDisplay;
|
|
pVoo->Height = mode->CrtcVDisplay;
|
|
if(!pVoo->Accel)
|
|
pVoo->FullHeight = mode->CrtcVDisplay;
|
|
|
|
mmio32_w(pVoo, 0x214, f1);
|
|
|
|
/* Voodoo 2 support */
|
|
if(pVoo->Voodoo2)
|
|
{
|
|
CARD32 f5 = mmio32_r(pVoo, 0x244);
|
|
mmio32_w(pVoo, 0x248, 0);
|
|
|
|
f5 &= ~0x05BF0000;
|
|
|
|
f5 &= ~(1<<22); /* For now */
|
|
|
|
if(mode->Flags & V_INTERLACE)
|
|
f5 |= 1<<26;
|
|
/* FIXME: is this H, V or both doublescan ?? */
|
|
if(mode->Flags & V_DBLSCAN)
|
|
f5 |= (1<<21) | (1<<20);
|
|
if(mode->Flags & V_PHSYNC)
|
|
f5 |= (1<<23);
|
|
if(mode->Flags & V_PVSYNC)
|
|
f5 |= (1<<24);
|
|
mmio32_w(pVoo, 0x244, f5);
|
|
}
|
|
wait_idle(pVoo);
|
|
mmio32_w(pVoo, 0x214, mmio32_r(pVoo,0x214) & ~0x100);
|
|
mmio32_w(pVoo, 0x210, 1 | (mmio32_r(pVoo,0x210) & ~6));
|
|
mmio32_w(pVoo, 0x218, mmio32_r(pVoo,0x218) | (1<<22));
|
|
|
|
pci_enable(pVoo, 0, 0, 1);
|
|
|
|
mmio32_w(pVoo, 0x114, 0x100);
|
|
pVoo->lfbMode = 0x100; /* Cached LFB mode, front, front, on */
|
|
|
|
/*
|
|
* Set a clipping rectangle. We really deeply emphatically
|
|
* don't want to write off screen otherwise.
|
|
*/
|
|
mmio32_w(pVoo, 0x118, mode->CrtcHDisplay);
|
|
mmio32_w(pVoo, 0x11C, mode->CrtcVDisplay);
|
|
mmio32_w(pVoo, 0x110, /*mmio32_r(pVoo, 0x110) | */0x201);
|
|
|
|
/*
|
|
* Set up the 2D engine drawing logic
|
|
*/
|
|
|
|
if(pVoo->Voodoo2)
|
|
{
|
|
mmio32_w_chuck(pVoo, 0x2C0, 0); /* Zero source */
|
|
mmio32_w_chuck(pVoo, 0x2C4, 0); /* Zero destination */
|
|
/* Use screen sized tiles for src/dst */
|
|
mmio32_w_chuck(pVoo, 0x2C8, (pVoo->Tiles << 16) | pVoo->Tiles);
|
|
mmio32_w_chuck(pVoo, 0x2D4, pVoo->Width);
|
|
mmio32_w_chuck(pVoo, 0x2D8, pVoo->FullHeight);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Probe and initialize a Voodoo 1 or Voodoo 2 that we found.
|
|
* We don't set up any video mode at this point.
|
|
*/
|
|
|
|
int VoodooHardwareInit(VoodooPtr pVoo)
|
|
{
|
|
vclock_enable(pVoo, 0);
|
|
pci_enable(pVoo, 1, 0, 0);
|
|
|
|
mmio32_w(pVoo, 0x214, mmio32_r(pVoo, 0x214) | 0x100);
|
|
wait_idle(pVoo);
|
|
|
|
mmio32_w(pVoo, 0x210, mmio32_r(pVoo, 0x210) | 7);
|
|
wait_idle(pVoo);
|
|
|
|
mmio32_w(pVoo, 0x218, mmio32_r(pVoo, 0x218) & ~(1<<22));
|
|
wait_idle(pVoo);
|
|
|
|
/* At this point we are basically shut down */
|
|
|
|
pci_enable(pVoo, 1, 1, 0);
|
|
|
|
pVoo->DAC = voodoo_find_dac(pVoo);
|
|
|
|
/* Graphics clock depends on the board */
|
|
pVoo->MaxClock = 50000;
|
|
if(pVoo->Voodoo2)
|
|
pVoo->MaxClock = 75000;
|
|
|
|
sst_calc_pll(pVoo->MaxClock, &pVoo->gClock);
|
|
voodoo_set_pll(pVoo, 1);
|
|
|
|
pci_enable(pVoo, 1, 0, 1);
|
|
|
|
mmio32_w(pVoo, 0x210, 0); /* 1 for VGA pass through */
|
|
wait_idle(pVoo);
|
|
mmio32_w(pVoo, 0x214, 0x1A8 | (1<<21) );
|
|
wait_idle(pVoo);
|
|
mmio32_w(pVoo, 0x218, 0x186000E0); /* RAM setup with fast ras, oe, fifo, refresh on and a 16mS refresh */
|
|
wait_idle(pVoo);
|
|
mmio32_w(pVoo, 0x21C, 0x40); /* Need to review with DRI */
|
|
wait_idle(pVoo);
|
|
mmio32_w(pVoo, 0x200, 2);
|
|
wait_idle(pVoo);
|
|
|
|
if(pVoo->Voodoo2)
|
|
{
|
|
mmio32_w(pVoo, 0x248, 0);
|
|
wait_idle(pVoo);
|
|
}
|
|
|
|
pci_enable(pVoo, 0, 0, 1);
|
|
vclock_enable(pVoo, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Voodoo exit logic
|
|
*/
|
|
|
|
void VoodooRestorePassThrough(VoodooPtr pVoo)
|
|
{
|
|
pci_enable(pVoo, 1, 0, 0);
|
|
mmio32_w(pVoo, 0x210, 0);
|
|
pci_enable(pVoo, 0, 0, 1);
|
|
}
|
|
|
|
/*
|
|
* Copiers for Voodoo1
|
|
*
|
|
* Voodoo1 has no CPU to screen blit, and also lacks SGRAM fill
|
|
*/
|
|
|
|
void VoodooCopy16(VoodooPtr pVoo, CARD32 x1, CARD32 y1, CARD32 w, CARD32 h, CARD32 spitch, unsigned char *src)
|
|
{
|
|
/* DWord copy pointer */
|
|
CARD32 *out = (CARD32 *)(pVoo->FBBase + y1 * pVoo->Pitch + x1 *2);
|
|
CARD32 *in = (CARD32 *)src;
|
|
/* DWords to skip */
|
|
CARD32 skipo = (pVoo->Pitch - w*2)>>2;
|
|
CARD32 skipi = (pVoo->ShadowPitch - w*2)>>2;
|
|
int ct;
|
|
|
|
/* LFB will do all our work for us */
|
|
|
|
mmio32_w(pVoo, 0x10C, 0);
|
|
mmio32_w(pVoo, 0x110, (1<<9)|1);
|
|
mmio32_w(pVoo, 0x114, (1<<8));
|
|
while(h > 0)
|
|
{
|
|
for(ct = 0; ct < w; ct+=2)
|
|
*out++=*in++;
|
|
in += skipi;
|
|
out += skipo;
|
|
h--;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Copiers for Voodoo 1 and Voodoo 2 24bit
|
|
*
|
|
* Voodoo1 has no CPU to screen blit, and also lacks SGRAM fill
|
|
* Voodoo2 has no read side 24bit, nor 24bit accelerator
|
|
*/
|
|
|
|
void VoodooCopy24(VoodooPtr pVoo, CARD32 x1, CARD32 y1, CARD32 w, CARD32 h, CARD32 spitch, unsigned char *src)
|
|
{
|
|
/* DWord copy pointer */
|
|
CARD32 *out = (CARD32 *)(pVoo->FBBase + y1 * pVoo->Pitch + x1 * 4);
|
|
CARD32 *in = (CARD32 *)src;
|
|
/* DWords to skip */
|
|
CARD32 skipo = (pVoo->Pitch - w*4)>>2;
|
|
CARD32 skipi = (pVoo->ShadowPitch - w*4)>>2;
|
|
int ct;
|
|
|
|
/* LFB will do all our work for us */
|
|
/* FIXME: Should we allow dither options ? */
|
|
|
|
mmio32_w(pVoo, 0x10C, 0);
|
|
mmio32_w(pVoo, 0x110, (1<<9)|1);
|
|
mmio32_w(pVoo, 0x114, (1<<8)|4);
|
|
while(h > 0)
|
|
{
|
|
for(ct = 0; ct < w; ct++)
|
|
*out++=*in++;
|
|
in += skipi;
|
|
out += skipo;
|
|
h--;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Use hardware clear. For Voodoo2 we want to use the SGRAM fill
|
|
* really. fbzMode bits 9/10 write to depth buffer, bit 14/15 to select
|
|
* the right buffer, bit 9 off for no dither, depth in zacolor, bits in
|
|
* colour1.
|
|
*
|
|
* load cliplr/lyhy and then fire.
|
|
*/
|
|
|
|
void VoodooClear(VoodooPtr pVoo)
|
|
{
|
|
memset(pVoo->FBBase,0, 0x400000);
|
|
}
|
|
|
|
/*
|
|
* Voodoo banking. The voodoo isn't exactly banked in the conventional
|
|
* sense but claiming to be banked allows us to use the back buffer
|
|
* as the pixcache, providing we are careful with our acceleration
|
|
* ops
|
|
*
|
|
* There are two banks. Bank 0 is the front buffer, bank 1 is the
|
|
* back buffer. We don't use the aux buffer. Additionally the
|
|
* back buffer in 1024x768 with 2Mbyte cards is only a partial buffer.
|
|
* (No SLI yet)
|
|
*
|
|
* Not yet used (TODO: figure out the offsets for the backbuffer layout)
|
|
* For now we work the screen as one deep display instead
|
|
*/
|
|
|
|
void VoodooReadBank(ScreenPtr pScreen, int bank)
|
|
{
|
|
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
|
|
VoodooPtr pVoo = VoodooPTR(pScrn);
|
|
if(bank)
|
|
{
|
|
mmio32_w(pVoo, 0x2C0, pVoo->Height);
|
|
pVoo->lfbMode |= (1<<6);
|
|
}
|
|
else
|
|
{
|
|
mmio32_w(pVoo, 0x2C0, 0);
|
|
pVoo->lfbMode &= ~(1<<6);
|
|
}
|
|
mmio32_w(pVoo, 0x114, pVoo->lfbMode);
|
|
}
|
|
|
|
void VoodooWriteBank(ScreenPtr pScreen, int bank)
|
|
{
|
|
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
|
|
VoodooPtr pVoo = VoodooPTR(pScrn);
|
|
if(bank)
|
|
{
|
|
mmio32_w(pVoo, 0x2C4, pVoo->Height);
|
|
pVoo->lfbMode |= (1<<4);
|
|
}
|
|
else
|
|
{
|
|
mmio32_w(pVoo, 0x2C4, 0);
|
|
pVoo->lfbMode &= ~(1<<4);
|
|
}
|
|
mmio32_w(pVoo, 0x114, pVoo->lfbMode);
|
|
}
|
|
|
|
void VoodooSync(ScrnInfoPtr pScrn)
|
|
{
|
|
VoodooPtr pVoo = VoodooPTR(pScrn);
|
|
/* FIXME: Check if cliprect dirty if so rewrite */
|
|
wait_idle(pVoo);
|
|
mmio32_w(pVoo, 0x10C, 0); /* Maybe flag this */
|
|
}
|