xserver-multidpi/hw/kdrive/savage/s3.c
2003-09-11 05:12:51 +00:00

1839 lines
48 KiB
C

/*
* Id: s3.c,v 1.3 1999/11/02 08:17:24 keithp Exp $
*
* Copyright 1999 SuSE, 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 name of SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* 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.
*
* Author: Keith Packard, SuSE, Inc.
*/
/* $RCSId: xc/programs/Xserver/hw/kdrive/savage/s3.c,v 1.4 2000/05/06 22:17:44 keithp Exp $ */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "s3.h"
#define REGISTERS_OFFSET (0x1000000)
#define PACKED_OFFSET (0x8100)
#define IOMAP_OFFSET (0x8000)
#define S3_MIN_CLOCK 250000
static void
_s3SetBlank (S3Ptr s3, S3Vga *s3vga, Bool blank)
{
CARD8 clock_mode;
s3SetImm(s3vga, s3_screen_off, blank ? 1 : 0);
}
Bool
s3CardInit (KdCardInfo *card)
{
S3CardInfo *s3c;
S3Ptr s3;
S3Vga *s3vga;
int size;
CARD8 *registers;
CARD32 s3FrameBuffer;
CARD32 s3Registers;
CARD8 *temp_buffer;
CARD32 max_memory;
VGA32 save_linear_window_size;
VGA32 save_enable_linear;
VGA32 save_register_lock_2;
VGA32 save_misc_output;
s3c = (S3CardInfo *) xalloc (sizeof (S3CardInfo));
if (!s3c)
{
goto bail0;
}
memset (s3c, '\0', sizeof (S3CardInfo));
card->driver = s3c;
#ifdef VXWORKS
s3c->bios_initialized = 0;
#else
s3c->bios_initialized = 1;
#endif
if (card->attr.naddr > 1 && card->attr.address[1])
{
s3FrameBuffer = card->attr.address[1];
s3Registers = card->attr.address[0];
max_memory = 32 * 1024 * 1024;
}
else
{
s3FrameBuffer = card->attr.address[0];
s3Registers = s3FrameBuffer + REGISTERS_OFFSET;
max_memory = 16 * 1024 * 1024;
}
#ifdef DEBUG
fprintf (stderr, "S3 at 0x%x/0x%x\n", s3Registers, s3FrameBuffer);
#endif
registers = KdMapDevice (s3Registers,
sizeof (S3) + PACKED_OFFSET);
if (!registers)
{
ErrorF ("Can't map s3 device\n");
goto bail2;
}
s3 = (S3Ptr) (registers + PACKED_OFFSET);
s3c->registers = registers;
s3c->s3 = s3;
s3vga = &s3c->s3vga;
s3RegInit (s3vga, (VGAVOL8 *) (registers + IOMAP_OFFSET));
if (!s3c->bios_initialized)
{
volatile CARD32 *wakeup;
wakeup = (volatile CARD32 *) (registers + 0x8510);
ErrorF ("Wakeup S3 chip at 0x%x\n", wakeup);
ErrorF ("Wakeup was 0x%x\n", *wakeup);
/* wakeup the chip */
*(volatile CARD32 *) (registers + 0x8510) = 1;
ErrorF ("Wakeup is 0x%x\n", *wakeup);
}
s3Set (s3vga, s3_io_addr_select, 1);
s3Set (s3vga, s3_enable_ram, 1);
VgaFlush (&s3vga->card);
save_register_lock_2 = s3Get (s3vga, s3_register_lock_2);
s3SetImm (s3vga, s3_register_lock_2, 0xa0);
save_linear_window_size = s3Get (s3vga, s3_linear_window_size);
save_enable_linear = s3Get (s3vga, s3_enable_linear);
s3Set (s3vga, s3_linear_window_size, 3);
s3Set (s3vga, s3_enable_linear, 1);
VgaFlush (&s3vga->card);
VgaFinish (&s3vga->card);
/*
* Can't trust S3 register value for frame buffer amount, must compute
*/
temp_buffer = KdMapDevice (s3FrameBuffer, max_memory);
s3c->memory = KdFrameBufferSize (temp_buffer, max_memory);
s3Set (s3vga, s3_linear_window_size, save_linear_window_size);
s3Set (s3vga, s3_enable_linear, save_enable_linear);
VgaFlush (&s3vga->card);
s3SetImm (s3vga, s3_register_lock_2, save_register_lock_2);
VgaFinish (&s3vga->card);
#ifdef DEBUG
fprintf (stderr, "Frame buffer 0x%x\n", s3c->memory);
#endif
KdUnmapDevice (temp_buffer, max_memory);
if (!s3c->memory)
{
ErrorF ("Can't detect s3 frame buffer at 0x%x\n", s3FrameBuffer);
goto bail3;
}
s3c->frameBuffer = KdMapDevice (s3FrameBuffer, s3c->memory);
if (!s3c->frameBuffer)
{
ErrorF ("Can't map s3 frame buffer\n");
goto bail3;
}
card->driver = s3c;
return TRUE;
bail3:
KdUnmapDevice ((void *) s3, sizeof (S3));
bail2:
bail1:
xfree (s3c);
bail0:
return FALSE;
}
Bool
s3ModeSupported (KdScreenInfo *screen,
const KdMonitorTiming *t)
{
if (screen->fb[1].depth)
{
/*
* Must have at least one true color stream
*/
if (screen->fb[0].depth <= 8 &&
screen->fb[1].depth <= 8)
return FALSE;
}
/* make sure the clock isn't too fast */
if (t->clock > S3_MAX_CLOCK * 2)
return FALSE;
/* width must be a multiple of 16 */
if (t->horizontal & 0xf)
return FALSE;
return TRUE;
}
Bool
s3ModeUsable (KdScreenInfo *screen)
{
KdCardInfo *card = screen->card;
S3CardInfo *s3c = (S3CardInfo *) card->driver;
int screen_size;
int pixel_width;
int byte_width;
int fb;
screen_size = 0;
for (fb = 0; fb < KD_MAX_FB && screen->fb[fb].depth; fb++)
{
if (screen->fb[fb].depth >= 24)
{
screen->fb[fb].depth = 24;
if (screen->fb[fb].bitsPerPixel != 24)
screen->fb[fb].bitsPerPixel = 32;
}
else if (screen->fb[fb].depth >= 16)
{
screen->fb[fb].depth = 16;
screen->fb[fb].bitsPerPixel = 16;
}
else if (screen->fb[fb].depth >= 15)
{
screen->fb[fb].depth = 15;
screen->fb[fb].bitsPerPixel = 16;
}
else
{
screen->fb[fb].depth = 8;
screen->fb[fb].bitsPerPixel = 8;
}
/*
* SGRAM requires stride % 64 == 0
*/
screen->fb[fb].pixelStride = (screen->width + 63) & ~63;
screen->fb[fb].byteStride = screen->fb[fb].pixelStride * (screen->fb[fb].bitsPerPixel >> 3);
screen_size += screen->fb[fb].byteStride * screen->height;
}
return screen_size <= s3c->memory;
}
Bool
s3ScreenInit (KdScreenInfo *screen)
{
KdCardInfo *card = screen->card;
S3CardInfo *s3c = (S3CardInfo *) card->driver;
S3ScreenInfo *s3s;
int memory;
int requested_memory;
int v_total, h_total;
int m, n, r;
int i;
const KdMonitorTiming *t;
int screen_size;
int fb;
int ma;
s3s = (S3ScreenInfo *) xalloc (sizeof (S3ScreenInfo));
if (!s3s)
return FALSE;
memset (s3s, '\0', sizeof (S3ScreenInfo));
#ifdef PHOENIX
screen->width = 1152;
screen->height = 900;
screen->rate = 85;
screen->depth = 32;
#endif
if (!screen->width || !screen->height)
{
screen->width = 800;
screen->height = 600;
screen->rate = 72;
}
if (!screen->fb[0].depth)
screen->fb[0].depth = 8;
t = KdFindMode (screen, s3ModeSupported);
screen->rate = t->rate;
screen->width = t->horizontal;
screen->height = t->vertical;
s3GetClock (t->clock, &m, &n, &r, 511, 127, 4, 250000);
#ifdef DEBUG
fprintf (stderr, "computed %d,%d,%d (%d)\n",
m, n, r, S3_CLOCK(m,n,r));
#endif
#if 0
/*
* Can only operate in pixel-doubled mode at 8 or 16 bits per pixel
*/
if (screen->depth > 16 && S3_CLOCK(m,n,r) > S3_MAX_CLOCK)
screen->depth = 16;
#endif
if (!KdTuneMode (screen, s3ModeUsable, s3ModeSupported))
{
xfree (s3s);
return FALSE;
}
s3s->fbmap[2] = -1;
if (screen->fb[1].depth)
{
if (screen->fb[0].bitsPerPixel >= 16)
{
s3s->fbmap[0] = 1;
s3s->fbmap[1] = 0;
}
else
{
s3s->fbmap[0] = 0;
s3s->fbmap[1] = 1;
}
}
else
{
s3s->fbmap[0] = 0;
s3s->fbmap[1] = -1;
}
screen_size = 0;
for (fb = 0; fb < KD_MAX_FB && screen->fb[fb].depth; fb++)
screen_size += screen->fb[fb].byteStride * screen->height;
memory = s3c->memory - screen_size;
/*
* Stick cursor at end of memory
*/
if (memory >= 2048)
{
s3s->cursor_base = s3c->frameBuffer + (s3c->memory - 2048);
memory -= 2048;
}
else
s3s->cursor_base = 0;
screen_size = 0;
for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
{
fb = s3s->fbmap[ma];
screen->fb[fb].frameBuffer = s3c->frameBuffer + screen_size;
screen_size += screen->fb[fb].byteStride * screen->height;
REGION_INIT(pScreen, (&s3s->region[fb]), NullBox, 0);
if (screen->fb[fb].bitsPerPixel == 8)
s3s->fb[ma].chroma_key = 0xff;
else
s3s->fb[ma].chroma_key = 0;
/*
* Use remaining memory for off-screen storage, but only use
* one piece (either right or bottom).
*/
if (memory >= screen->fb[fb].byteStride * S3_TILE_SIZE)
{
s3s->fb[ma].offscreen = screen->fb[fb].frameBuffer;
s3s->fb[ma].offscreen_x = 0;
s3s->fb[ma].offscreen_y = screen->height;
s3s->fb[ma].offscreen_width = screen->fb[fb].pixelStride;
s3s->fb[ma].offscreen_height = S3_TILE_SIZE;
memory -= s3s->fb[ma].offscreen_height * screen->fb[fb].byteStride;
screen_size += s3s->fb[ma].offscreen_height * screen->fb[fb].byteStride;
}
else
s3s->fb[ma].offscreen = 0;
switch (screen->fb[fb].depth) {
case 8:
screen->fb[fb].visuals = ((1 << StaticGray) |
(1 << GrayScale) |
(1 << StaticColor) |
(1 << PseudoColor) |
(1 << TrueColor) |
(1 << DirectColor));
screen->fb[fb].blueMask = 0x00;
screen->fb[fb].greenMask = 0x00;
screen->fb[fb].redMask = 0x00;
break;
case 15:
screen->fb[fb].visuals = (1 << TrueColor);
screen->fb[fb].blueMask = 0x001f;
screen->fb[fb].greenMask = 0x03e0;
screen->fb[fb].redMask = 0x7c00;
break;
case 16:
screen->fb[fb].visuals = (1 << TrueColor);
screen->fb[fb].blueMask = 0x001f;
screen->fb[fb].greenMask = 0x07e0;
screen->fb[fb].redMask = 0xf800;
break;
case 24:
screen->fb[fb].visuals = (1 << TrueColor);
screen->fb[fb].blueMask = 0x0000ff;
screen->fb[fb].greenMask = 0x00ff00;
screen->fb[fb].redMask = 0xff0000;
break;
}
}
screen->driver = s3s;
return TRUE;
}
typedef struct _biosInit {
VGA16 reg;
VGA8 value;
} s3BiosInit;
s3BiosInit s3BiosReg[] = {
S3_SR +0x15, 0x23,
S3_MISC_OUT, 0x2f,
0xffff, 1,
S3_SR +0x15, 0x03,
S3_SR + 0x0, 0x03,
S3_SR + 0x1, 0x00,
S3_SR + 0x2, 0x03,
S3_SR + 0x3, 0x00,
S3_SR + 0x4, 0x02,
S3_SR + 0x5, 0x05,
S3_SR + 0x6, 0x06,
S3_SR + 0x7, 0x07,
/* S3_SR + 0x8, 0x06, */
S3_SR + 0x9, 0x00,
S3_SR + 0xa, 0x0a,
S3_SR + 0xb, 0x00,
S3_SR + 0xc, 0x0c,
S3_SR + 0xd, 0x00,
S3_SR + 0xe, 0x0e,
S3_SR + 0xf, 0x0f,
/* S3_SR +0x10, 0x00, */
/* S3_SR +0x11, 0x0c, */
S3_SR +0x12, 0x01,
S3_SR +0x13, 0x52,
S3_SR +0x14, 0x00,
/* S3_SR +0x15, 0x03, */
S3_SR +0x16, 0xc5,
S3_SR +0x17, 0xfc,
S3_SR +0x18, 0x40,
S3_SR +0x19, 0x00,
S3_SR +0x1a, 0x01,
S3_SR +0x1b, 0x02,
S3_SR +0x1c, 0x5d,
S3_SR +0x1d, 0x00,
S3_SR +0x1e, 0x00,
S3_SR +0x1f, 0x00,
S3_SR +0x20, 0x20,
S3_SR +0x21, 0x21,
S3_SR +0x22, 0x22,
S3_SR +0x23, 0x23,
S3_SR +0x24, 0x24,
S3_SR +0x25, 0x25,
S3_SR +0x26, 0x26,
S3_SR +0x27, 0x04,
S3_SR +0x28, 0xff,
S3_SR +0x29, 0x00,
S3_SR +0x2a, 0x2a,
S3_SR +0x2b, 0x2b,
S3_SR +0x2c, 0x2c,
S3_SR +0x2d, 0x2d,
S3_SR +0x2e, 0x2e,
S3_SR +0x2f, 0x2f,
S3_SR +0x30, 0x00,
S3_SR +0x31, 0x06,
S3_SR +0x32, 0x41,
S3_SR +0x33, 0x67,
S3_SR +0x34, 0x00,
S3_SR +0x35, 0x00,
S3_SR +0x36, 0x01,
S3_SR +0x37, 0x52,
S3_SR +0x38, 0x5d,
S3_SR +0x39, 0x05,
S3_SR +0x3a, 0x3a,
S3_SR +0x3b, 0x3b,
S3_SR +0x3c, 0x3c,
S3_SR +0x3d, 0x00,
S3_SR +0x3e, 0x3e,
S3_SR +0x3f, 0x00,
S3_SR +0x40, 0x40,
S3_SR +0x41, 0x41,
S3_SR +0x42, 0x42,
S3_SR +0x43, 0x43,
S3_SR +0x44, 0x44,
S3_SR +0x45, 0x45,
S3_SR +0x46, 0x46,
S3_SR +0x47, 0x47,
S3_SR +0x48, 0x48,
S3_SR +0x49, 0x49,
S3_SR +0x4a, 0x4a,
S3_SR +0x4b, 0x4b,
S3_SR +0x4c, 0x4c,
S3_SR +0x4d, 0x4d,
S3_SR +0x4e, 0x4e,
S3_SR +0x4f, 0x4f,
S3_SR +0x50, 0x00,
S3_SR +0x51, 0x00,
S3_SR +0x52, 0x00,
S3_SR +0x53, 0x00,
S3_SR +0x54, 0x00,
S3_SR +0x55, 0x00,
S3_SR +0x56, 0x00,
S3_SR +0x57, 0x00,
S3_SR +0x58, 0x00,
S3_SR +0x59, 0x70,
S3_SR +0x5a, 0x38,
S3_SR +0x5b, 0x08,
S3_SR +0x5c, 0x77,
S3_SR +0x5d, 0x77,
S3_SR +0x5e, 0x00,
S3_SR +0x5f, 0x00,
S3_SR +0x60, 0xff,
S3_SR +0x61, 0xbf,
S3_SR +0x62, 0xff,
S3_SR +0x63, 0xff,
S3_SR +0x64, 0xf7,
S3_SR +0x65, 0xff,
S3_SR +0x66, 0xff,
S3_SR +0x67, 0xff,
S3_SR +0x68, 0xff,
S3_SR +0x69, 0xff,
S3_SR +0x6a, 0xff,
S3_SR +0x6b, 0xff,
S3_SR +0x6c, 0xff,
S3_SR +0x6d, 0xff,
S3_SR +0x6e, 0x9b,
S3_SR +0x6f, 0xbf,
S3_AR + 0x00, 0x00,
S3_AR + 0x01, 0x01,
S3_AR + 0x02, 0x02,
S3_AR + 0x03, 0x03,
S3_AR + 0x04, 0x04,
S3_AR + 0x05, 0x05,
S3_AR + 0x06, 0x06,
S3_AR + 0x07, 0x07,
S3_AR + 0x08, 0x08,
S3_AR + 0x09, 0x09,
S3_AR + 0x0a, 0x0a,
S3_AR + 0x0b, 0x0b,
S3_AR + 0x0c, 0x0c,
S3_AR + 0x0d, 0x0d,
S3_AR + 0x0e, 0x0e,
S3_AR + 0x0f, 0x0f,
S3_AR + 0x10, 0x05,
S3_AR + 0x11, 0x00,
S3_AR + 0x12, 0x0f,
S3_AR + 0x13, 0x08,
S3_AR + 0x14, 0x00,
S3_GR + 0x00, 0x00,
S3_GR + 0x01, 0x00,
S3_GR + 0x02, 0x00,
S3_GR + 0x03, 0x00,
S3_GR + 0x04, 0x00,
S3_GR + 0x05, 0x10,
S3_GR + 0x06, 0x0e,
S3_GR + 0x07, 0x00,
S3_CR + 0x00, 0x5f,
S3_CR + 0x01, 0x4f,
S3_CR + 0x02, 0x50,
S3_CR + 0x03, 0x82,
S3_CR + 0x04, 0x55,
S3_CR + 0x05, 0x81,
S3_CR + 0x06, 0xbf,
S3_CR + 0x07, 0x1f,
S3_CR + 0x08, 0x00,
S3_CR + 0x09, 0x4f,
S3_CR + 0x0a, 0x0d,
S3_CR + 0x0b, 0x0e,
S3_CR + 0x0c, 0x00,
S3_CR + 0x0d, 0x00,
S3_CR + 0x0e, 0x3f,
S3_CR + 0x0f, 0xff,
S3_CR + 0x10, 0x9c,
S3_CR + 0x11, 0x0e,
S3_CR + 0x12, 0x8f,
S3_CR + 0x13, 0x28,
S3_CR + 0x14, 0x1f,
S3_CR + 0x15, 0x96,
S3_CR + 0x16, 0xb9,
S3_CR + 0x17, 0xa3,
S3_CR + 0x18, 0xff,
S3_CR + 0x19, 0xdf,
S3_CR + 0x1a, 0xdf,
S3_CR + 0x1b, 0xdf,
S3_CR + 0x1c, 0xdf,
S3_CR + 0x1d, 0xdf,
S3_CR + 0x1e, 0xdf,
S3_CR + 0x1f, 0xdf,
S3_CR + 0x20, 0xdf,
S3_CR + 0x21, 0x00,
/* S3_CR + 0x22, 0x07, */
S3_CR + 0x23, 0x00,
S3_CR + 0x24, 0xdf,
S3_CR + 0x25, 0xdf,
S3_CR + 0x26, 0x00,
S3_CR + 0x27, 0xdf,
S3_CR + 0x28, 0xdf,
S3_CR + 0x29, 0xdf,
S3_CR + 0x2a, 0xdf,
S3_CR + 0x2b, 0xdf,
S3_CR + 0x2c, 0xdf,
S3_CR + 0x2d, 0x8a,
S3_CR + 0x2e, 0x22,
S3_CR + 0x2f, 0x02,
S3_CR + 0x30, 0xe1,
S3_CR + 0x31, 0x05,
S3_CR + 0x32, 0x40,
S3_CR + 0x33, 0x08,
S3_CR + 0x34, 0x00,
S3_CR + 0x35, 0x00,
S3_CR + 0x36, 0xbf,
S3_CR + 0x37, 0x9b,
/* S3_CR + 0x38, 0x7b, */
/* S3_CR + 0x39, 0xb8, */
S3_CR + 0x3a, 0x45,
S3_CR + 0x3b, 0x5a,
S3_CR + 0x3c, 0x10,
S3_CR + 0x3d, 0x00,
S3_CR + 0x3e, 0xfd,
S3_CR + 0x3f, 0x00,
S3_CR + 0x40, 0x00,
S3_CR + 0x41, 0x92,
S3_CR + 0x42, 0xc0,
S3_CR + 0x43, 0x68,
S3_CR + 0x44, 0xff,
S3_CR + 0x45, 0xe8,
S3_CR + 0x46, 0xff,
S3_CR + 0x47, 0xff,
S3_CR + 0x48, 0xf8,
S3_CR + 0x49, 0xff,
S3_CR + 0x4a, 0xfe,
S3_CR + 0x4b, 0xff,
S3_CR + 0x4c, 0xff,
S3_CR + 0x4d, 0xff,
S3_CR + 0x4e, 0xff,
S3_CR + 0x4f, 0xff,
S3_CR + 0x50, 0x00,
S3_CR + 0x51, 0x00,
S3_CR + 0x52, 0x00,
S3_CR + 0x53, 0x00,
S3_CR + 0x54, 0x00,
S3_CR + 0x55, 0x00,
S3_CR + 0x56, 0x00,
S3_CR + 0x57, 0x00,
#if 0
S3_CR + 0x58, 0x00,
S3_CR + 0x59, 0xf0,
#endif
S3_CR + 0x5a, 0x00,
S3_CR + 0x5b, 0x00,
#if 0
S3_CR + 0x5c, 0x00,
#endif
S3_CR + 0x5d, 0x00,
S3_CR + 0x5e, 0x00,
S3_CR + 0x5f, 0x00,
S3_CR + 0x60, 0x09,
S3_CR + 0x61, 0x9d,
S3_CR + 0x62, 0xff,
S3_CR + 0x63, 0x00,
S3_CR + 0x64, 0xfd,
S3_CR + 0x65, 0x04,
S3_CR + 0x66, 0x88,
S3_CR + 0x67, 0x00,
S3_CR + 0x68, 0x7f,
S3_CR + 0x69, 0x00,
S3_CR + 0x6a, 0x00,
S3_CR + 0x6b, 0x00,
S3_CR + 0x6c, 0x00,
S3_CR + 0x6d, 0x11,
S3_CR + 0x6e, 0xff,
S3_CR + 0x6f, 0xfe,
S3_CR + 0x70, 0x30,
S3_CR + 0x71, 0xc0,
S3_CR + 0x72, 0x07,
S3_CR + 0x73, 0x1f,
S3_CR + 0x74, 0x1f,
S3_CR + 0x75, 0x1f,
S3_CR + 0x76, 0x0f,
S3_CR + 0x77, 0x1f,
S3_CR + 0x78, 0x01,
S3_CR + 0x79, 0x01,
S3_CR + 0x7a, 0x1f,
S3_CR + 0x7b, 0x1f,
S3_CR + 0x7c, 0x17,
S3_CR + 0x7d, 0x17,
S3_CR + 0x7e, 0x17,
S3_CR + 0x7f, 0xfd,
S3_CR + 0x80, 0x00,
S3_CR + 0x81, 0x92,
S3_CR + 0x82, 0x10,
S3_CR + 0x83, 0x07,
S3_CR + 0x84, 0x42,
S3_CR + 0x85, 0x00,
S3_CR + 0x86, 0x00,
S3_CR + 0x87, 0x00,
S3_CR + 0x88, 0x10,
S3_CR + 0x89, 0xfd,
S3_CR + 0x8a, 0xfd,
S3_CR + 0x8b, 0xfd,
S3_CR + 0x8c, 0xfd,
S3_CR + 0x8d, 0xfd,
S3_CR + 0x8e, 0xfd,
S3_CR + 0x8f, 0xfd,
S3_CR + 0x90, 0x00,
S3_CR + 0x91, 0x4f,
S3_CR + 0x92, 0x10,
S3_CR + 0x93, 0x00,
S3_CR + 0x94, 0xfd,
S3_CR + 0x95, 0xfd,
S3_CR + 0x96, 0xfd,
S3_CR + 0x97, 0xfd,
S3_CR + 0x98, 0xfd,
S3_CR + 0x99, 0xff,
S3_CR + 0x9a, 0xfd,
S3_CR + 0x9b, 0xff,
S3_CR + 0x9c, 0xfd,
S3_CR + 0x9d, 0xfd,
S3_CR + 0x9e, 0xfd,
S3_CR + 0x9f, 0xff,
S3_CR + 0xa0, 0x0f,
#if 0
S3_CR + 0xa1, 0x00,
S3_CR + 0xa2, 0x00,
S3_CR + 0xa3, 0x00,
S3_CR + 0xa4, 0x55,
#endif
S3_CR + 0xa5, 0x09,
S3_CR + 0xa6, 0x20,
#if 0
S3_CR + 0xa7, 0x00,
S3_CR + 0xa8, 0x00,
S3_CR + 0xa9, 0x00,
S3_CR + 0xaa, 0x00,
S3_CR + 0xab, 0x00,
S3_CR + 0xac, 0x00,
S3_CR + 0xad, 0x00,
S3_CR + 0xae, 0x00,
S3_CR + 0xaf, 0x00,
S3_CR + 0xb0, 0xff,
#endif
S3_CR + 0xb1, 0x0e,
#if 0
S3_CR + 0xb2, 0x55,
S3_CR + 0xb3, 0x00,
S3_CR + 0xb4, 0x55,
S3_CR + 0xb5, 0x00,
S3_CR + 0xb6, 0x00,
#endif
S3_CR + 0xb7, 0x84,
#if 0
S3_CR + 0xb8, 0xff,
S3_CR + 0xb9, 0xff,
S3_CR + 0xba, 0xff,
S3_CR + 0xbb, 0xff,
S3_CR + 0xbc, 0xff,
S3_CR + 0xbd, 0xff,
S3_CR + 0xbe, 0xff,
S3_CR + 0xbf, 0xff,
#endif
S3_SR +0x15, 0x23,
0xffff, 1,
S3_SR +0x15, 0x03,
0xffff, 1,
};
#define S3_NUM_BIOS_REG (sizeof (s3BiosReg) / sizeof (s3BiosReg[0]))
typedef struct _bios32Init {
VGA16 offset;
VGA32 value;
} s3Bios32Init;
s3Bios32Init s3Bios32Reg[] = {
0x8168, 0x00000000,
0x816c, 0x00000001,
0x8170, 0x00000000,
0x8174, 0x00000000,
0x8178, 0x00000000,
0x817c, 0x00000000,
#if 0
0x8180, 0x00140000,
0x8184, 0x00000000,
0x8188, 0x00000000,
0x8190, 0x00000000,
0x8194, 0x00000000,
0x8198, 0x00000000,
0x819c, 0x00000000,
0x81a0, 0x00000000,
#endif
0x81c0, 0x00000000,
0x81c4, 0x01fbffff,
0x81c8, 0x00f7ffbf,
0x81cc, 0x00f7ff00,
0x81d0, 0x11ffff7f,
0x81d4, 0x7fffffdf,
0x81d8, 0xfdfff9ff,
0x81e0, 0xfd000000,
0x81e4, 0x00000000,
0x81e8, 0x00000000,
0x81ec, 0x00010000,
0x81f0, 0x07ff057f,
0x81f4, 0x07ff07ff,
0x81f8, 0x00000000,
0x81fc, 0x00000000,
0x8200, 0x00000000,
0x8204, 0x00000000,
0x8208, 0x33000000,
0x820c, 0x7f000000,
0x8210, 0x80000000,
0x8214, 0x00000000,
0x8218, 0xffffffff,
0x8300, 0xff007fef,
0x8304, 0xfffdf7bf,
0x8308, 0xfdfffbff,
};
#define S3_NUM_BIOS32_REG (sizeof (s3Bios32Reg) / sizeof (s3Bios32Reg[0]))
/*
* Initialize the card precisely as the bios does
*/
s3DoBiosInit (KdCardInfo *card)
{
S3CardInfo *s3c = card->driver;
CARD32 *regs = (CARD32 *) s3c->registers;
S3Vga *s3vga = &s3c->s3vga;
int r;
for (r = 0; r < S3_NUM_BIOS_REG; r++)
{
if (s3BiosReg[r].reg == 0xffff)
sleep (s3BiosReg[r].value);
else
VgaStore (&s3vga->card, s3BiosReg[r].reg, s3BiosReg[r].value);
}
VgaStore (&s3vga->card, S3_SR+0x10, 0x22);
VgaStore (&s3vga->card, S3_SR+0x11, 0x44);
VgaStore (&s3vga->card, S3_SR+0x15, 0x01);
sleep (1);
VgaStore (&s3vga->card, S3_SR+0x15, 0x03);
VgaStore (&s3vga->card, S3_CR+0x6f, 0xff);
VgaStore (&s3vga->card, S3_CR+0x3f, 0x3f);
sleep (1);
VgaStore (&s3vga->card, S3_CR+0x3f, 0x00);
VgaStore (&s3vga->card, S3_CR+0x6f, 0xfe);
VgaInvalidate (&s3vga->card);
for (r = 0; r < S3_NUM_BIOS32_REG; r++)
regs[s3Bios32Reg[r].offset/4] = s3Bios32Reg[r].value;
}
void
s3Preserve (KdCardInfo *card)
{
S3CardInfo *s3c = card->driver;
S3Ptr s3 = s3c->s3;
S3Vga *s3vga = &s3c->s3vga;
S3Save *save = &s3c->save;
CARD8 t1, t2;
CARD8 *cursor_base;
CARD8 streams_mode;
s3Save (s3vga);
if (!s3c->bios_initialized)
s3DoBiosInit (card);
_s3SetBlank (s3, s3vga, TRUE);
/*
* Preserve the first part of the frame buffer which holds
* the text mode fonts and data
*/
s3Set (s3vga, s3_linear_window_size, 3);
s3Set (s3vga, s3_enable_linear, 1);
VgaFlush (&s3vga->card);
memcpy (save->text_save, s3c->frameBuffer, S3_TEXT_SAVE);
/*
* Preserve graphics engine state
*/
save->alt_mix = s3->alt_mix;
save->write_mask = s3->write_mask;
save->fg = s3->fg;
save->bg = s3->bg;
/*
* Preserve streams processor state
*/
streams_mode = s3Get (s3vga, s3_streams_mode);
s3SetImm (s3vga, s3_streams_mode, 3);
save->global_bitmap_1 = s3->global_bitmap_1;
save->global_bitmap_2 = s3->global_bitmap_2;
save->adv_func_cntl = s3->adv_func_cntl;
save->primary_bitmap_1 = s3->primary_bitmap_1;
save->primary_bitmap_2 = s3->primary_bitmap_2;
save->secondary_bitmap_1 = s3->secondary_bitmap_1;
save->secondary_bitmap_2 = s3->secondary_bitmap_2;
save->primary_stream_control = s3->primary_stream_control;
save->blend_control = s3->blend_control;
save->primary_stream_addr_0 = s3->primary_stream_addr_0;
save->primary_stream_addr_1 = s3->primary_stream_addr_1;
save->primary_stream_stride = s3->primary_stream_stride;
save->primary_stream_xy = s3->primary_stream_xy;
save->primary_stream_size = s3->primary_stream_size;
save->primary_stream_mem = s3->primary_stream_mem;
save->secondary_stream_xy = s3->secondary_stream_xy;
save->secondary_stream_size = s3->secondary_stream_size;
save->streams_fifo = s3->streams_fifo;
s3SetImm (s3vga, s3_streams_mode, streams_mode);
_s3SetBlank (s3, s3vga, FALSE);
}
/*
* Enable the card for rendering. Manipulate the initial settings
* of the card here.
*/
int s3CpuTimeout, s3AccelTimeout;
void
s3SetGlobalBitmap (ScreenPtr pScreen, int ma)
{
KdScreenPriv(pScreen);
s3ScreenInfo (pScreenPriv);
if (s3s->current_ma != ma)
{
s3CardInfo (pScreenPriv);
S3Vga *s3vga = &s3c->s3vga;
S3Ptr s3 = s3c->s3;
CARD32 gb1, gb2;
int depth;
int length;
KdCheckSync (pScreen);
switch (s3s->fb[ma].accel_bpp) {
case 8:
case 24:
length = 0;
break;
case 16:
length = 1;
break;
case 32:
length = 3;
break;
}
s3SetImm (s3vga, s3_pixel_length, length);
gb1 = s3s->fb[ma].bitmap_offset;
gb2 = ((1 << 0) |
(0 << 2) |
(1 << 3) |
((s3s->fb[ma].accel_stride >> 4) << 4) |
(s3s->fb[ma].accel_bpp << 16) |
(0 << 24) |
(1 << 28));
s3->global_bitmap_1 = gb1;
s3->global_bitmap_2 = gb2;
s3->global_bitmap_2 = gb2;
s3s->current_ma = ma;
}
}
Bool
s3Enable (ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
KdCardInfo *card = pScreenPriv->card;
KdScreenInfo *screen = pScreenPriv->screen;
s3CardInfo (pScreenPriv);
s3ScreenInfo (pScreenPriv);
S3Vga *s3vga = &s3c->s3vga;
S3Ptr s3 = s3c->s3;
int hactive, hblank, hfp, hbp;
int vactive, vblank, vfp, vbp;
int hsize;
int h_total;
int h_display_end;
int h_blank_start;
int h_blank_end;
int h_sync_start;
int h_sync_end;
int h_screen_off;
int h_start_fifo_fetch;
int primary_stream_l1[KD_MAX_FB];
int v_total;
int v_retrace_start;
int v_retrace_end;
int v_display_end;
int v_blank_start;
int v_blank_end;
int v_blank_start_adjust = 0;
int v_blank_end_adjust = 0;
int h_blank_start_adjust = 0;
int h_blank_end_adjust = 0;
int h_sync_start_adjust = 0;
int h_sync_end_adjust = 0;
int h_start_fifo_fetch_adjust = 0;
int h_sync_extend;
int h_blank_extend;
int i;
CARD16 cursor_address;
const KdMonitorTiming *t;
int m, n, r;
Bool clock_double;
int cpu_timeout;
int accel_timeout;
int bytes_per_ms;
CARD32 control[2];
int fb;
int ma;
s3s->primary_depth = screen->fb[s3s->fbmap[0]].depth;
s3s->use_streams = TRUE;
t = KdFindMode (screen, s3ModeSupported);
hfp = t->hfp;
hbp = t->hbp;
hblank = t->hblank;
hactive = t->horizontal;
vfp = t->vfp;
vbp = t->vbp;
vblank = t->vblank;
vactive = t->vertical;
m = s3Get (s3vga, s3_dclk_m);
n = s3Get (s3vga, s3_dclk_n);
r = s3Get (s3vga, s3_dclk_r);
#define DEBUG_CLOCK
#ifdef DEBUG_CLOCK
fprintf (stderr, "old clock %d, %d, %d (%d)\n", m, n, r, S3_CLOCK(m,n,r));
#endif
clock_double = FALSE;
s3GetClock (t->clock, &m, &n, &r, 511, 127, 4, 250000);
if (S3_CLOCK(m,n,r) > S3_MAX_CLOCK && !s3s->use_streams)
clock_double = TRUE;
s3Set (s3vga, s3_clock_select, 3);
s3Set (s3vga, s3_dclk_m, m);
s3Set (s3vga, s3_dclk_n, n);
s3Set (s3vga, s3_dclk_r, r);
#ifdef DEBUG_CLOCK
fprintf (stderr, "new clock %d, %d, %d (%d)\n", m, n, r, S3_CLOCK(m,n,r));
#endif
if (s3s->use_streams)
{
s3Set (s3vga, s3_streams_mode, 3);
s3Set (s3vga, s3_enable_l1_parameter, 1);
}
else
{
s3Set (s3vga, s3_streams_mode, 0);
s3Set (s3vga, s3_enable_l1_parameter, 0);
}
s3Set (s3vga, s3_flat_panel_output_control_1, 0);
s3Set (s3vga, s3_flat_panel_output_control_2, 0);
s3Set (s3vga, s3_select_graphics_mode, 1);
s3Set (s3vga, s3_enable_blinking, 0);
s3Set (s3vga, s3_enable_vga_16bit, 0);
s3Set (s3vga, s3_enhanced_memory_mapping, 1);
s3Set (s3vga, s3_enable_sff, 1);
s3Set (s3vga, s3_enable_2d_access, 1);
s3Set (s3vga, s3_2bk_cga, 1);
s3Set (s3vga, s3_4bk_hga, 1);
s3Set (s3vga, s3_v_total_double, 0);
s3Set (s3vga, s3_address_16k_wrap, 1);
s3Set (s3vga, s3_word_mode, 0);
s3Set (s3vga, s3_byte_mode, 1);
s3Set (s3vga, s3_hardware_reset, 1);
s3Set (s3vga, s3_max_scan_line, 0);
s3Set (s3vga, s3_linear_window_size, 3);
s3Set (s3vga, s3_enable_linear, 1);
s3Set (s3vga, s3_enable_2d_3d, 1);
s3Set (s3vga, s3_refresh_control, 1);
s3Set (s3vga, s3_disable_pci_read_bursts, 0);
s3Set (s3vga, s3_pci_disconnect_enable, 1);
s3Set (s3vga, s3_primary_load_control, 0);
s3Set (s3vga, s3_secondary_load_control, 0);
s3Set (s3vga, s3_pci_retry_enable, 1);
s3Set (s3vga, s3_enable_256, 1);
s3Set (s3vga, s3_border_select, 1); /* eliminate white border */
s3SetImm (s3vga, s3_lock_palette, 0); /* unlock palette/border regs */
s3Set (s3vga, s3_disable_v_retrace_int, 1);
if (t->hpol == KdSyncPositive)
s3Set (s3vga, s3_horz_sync_neg, 0);
else
s3Set (s3vga, s3_horz_sync_neg, 1);
if (t->vpol == KdSyncPositive)
s3Set (s3vga, s3_vert_sync_neg, 0);
else
s3Set (s3vga, s3_vert_sync_neg, 1);
s3Set (s3vga, s3_dot_clock_8, 1);
s3Set (s3vga, s3_enable_write_plane, 0xf);
s3Set (s3vga, s3_extended_memory_access, 1);
s3Set (s3vga, s3_sequential_addressing_mode, 1);
s3Set (s3vga, s3_select_chain_4_mode, 1);
s3Set (s3vga, s3_linear_addressing_control, 1);
s3Set (s3vga, s3_enable_gamma_correction, 0);
s3Set (s3vga, s3_enable_8_bit_luts, 1);
s3Set (s3vga, s3_dclk_invert, 0);
s3Set (s3vga, s3_enable_clock_double, 0);
s3Set (s3vga, s3_dclk_over_2, 0);
s3Set (s3vga, s3_delay_h_enable, 0);
s3Set (s3vga, s3_sdclk_skew, 0);
s3Set (s3vga, s3_dac_mask, 0xff);
#if 0
#ifdef DEBUG_CLOCK
m = s3Get (s3vga, s3_mclk_m);
n = s3Get (s3vga, s3_mclk_n);
r = s3Get (s3vga, s3_mclk_r);
fprintf (stderr, "old mclk %d, %d, %d (%d)\n", m, n, r, S3_CLOCK(m,n,r));
#endif
s3GetClock (125282, &m, &n, &r, 127, 31, 3, 250000);
#ifdef DEBUG_CLOCK
fprintf (stderr, "new mclk %d, %d, %d (%d)\n", m, n, r,S3_CLOCK(m,n,r));
#endif
s3Set (s3vga, s3_mclk_m, m);
s3Set (s3vga, s3_mclk_n, n);
s3Set (s3vga, s3_mclk_r, r);
#ifdef DEBUG_CLOCK
m = s3Get (s3vga, s3_eclk_m);
n = s3Get (s3vga, s3_eclk_n);
r = s3Get (s3vga, s3_eclk_r);
fprintf (stderr, "old eclk %d, %d, %d (%d)\n", m, n, r, S3_CLOCK(m,n,r));
#endif
#define S3_ECLK 125282
s3GetClock (S3_ECLK, &m, &n, &r, 127, 31, 3, 250000);
#ifdef DEBUG_CLOCK
fprintf (stderr, "new eclk %d, %d, %d (%d)\n", m, n, r,S3_CLOCK(m,n,r));
#endif
s3Set (s3vga, s3_eclk_m, m);
s3Set (s3vga, s3_eclk_n, n);
s3Set (s3vga, s3_eclk_r, r);
#endif
/*
* Compute character lengths for horizontal timing values
*/
hactive = screen->width / 8;
hblank /= 8;
hfp /= 8;
hbp /= 8;
/*
* Set pixel size, choose clock doubling mode
*/
bytes_per_ms = 0;
for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
{
fb = s3s->fbmap[ma];
s3s->fb[ma].accel_bpp = screen->fb[fb].bitsPerPixel;
s3s->fb[ma].accel_stride = screen->fb[fb].pixelStride;
s3s->fb[ma].bitmap_offset = screen->fb[fb].frameBuffer - s3c->frameBuffer;
switch (s3s->fb[ma].accel_bpp) {
case 8:
h_screen_off = hactive;
s3Set (s3vga, s3_pixel_length, 0);
s3Set (s3vga, s3_color_mode, 0);
control[ma] = 0;
/*
* Set up for double-pixel mode, switch color modes,
* divide the dclk and delay h blank by 2 dclks
*/
if (clock_double)
{
s3Set (s3vga, s3_color_mode, 1);
s3Set (s3vga, s3_dclk_over_2, 1);
s3Set (s3vga, s3_enable_clock_double, 1);
s3Set (s3vga, s3_h_skew, 1);
h_blank_start_adjust = -3;
h_blank_end_adjust = -4;
s3Set (s3vga, s3_border_select, 0);
}
break;
case 16:
h_screen_off = hactive * 2;
s3Set (s3vga, s3_pixel_length, 1);
if (screen->fb[fb].depth == 15)
control[ma] = 3 << 24;
else
control[ma] = 5 << 24;
if (clock_double)
{
if (screen->fb[fb].depth == 15)
s3Set (s3vga, s3_color_mode, 3);
else
s3Set (s3vga, s3_color_mode, 5);
s3Set (s3vga, s3_dclk_over_2, 1);
s3Set (s3vga, s3_enable_clock_double, 1);
s3Set (s3vga, s3_border_select, 0);
h_blank_start_adjust = 4;
h_blank_end_adjust = -4;
}
else
{
if (screen->fb[fb].depth == 15)
s3Set (s3vga, s3_color_mode, 2);
else
s3Set (s3vga, s3_color_mode, 4);
s3Set (s3vga, s3_dclk_over_2, 0);
s3Set (s3vga, s3_enable_clock_double, 0);
s3Set (s3vga, s3_delay_blank, 0);
}
break;
case 24:
control[ma] = 6 << 24;
h_screen_off = hactive * 3;
s3s->fb[ma].accel_bpp = 8;
s3s->fb[ma].accel_stride = screen->fb[fb].pixelStride * 3;
break;
case 32:
control[ma] = 7 << 24;
h_screen_off = hactive * 4;
s3Set (s3vga, s3_pixel_length, 3);
s3Set (s3vga, s3_color_mode, 0xd);
break;
}
bytes_per_ms += t->clock * (screen->fb[fb].bitsPerPixel / 8);
primary_stream_l1[ma] = (screen->width * screen->fb[fb].bitsPerPixel / (8 * 8)) - 1;
}
/*
* X server starts frame buffer at top of memory
*/
s3Set (s3vga, s3_start_address, 0);
/*
* Set various registers to avoid snow on the screen
*/
fprintf (stderr, "bytes_per_ms %d\n", bytes_per_ms);
fprintf (stderr, "primary 0x%x master 0x%x command 0x%x lpb 0x%x cpu 0x%x 2d 0x%x\n",
s3Get (s3vga, s3_primary_stream_timeout),
s3Get (s3vga, s3_master_control_unit_timeout),
s3Get (s3vga, s3_command_buffer_timeout),
s3Get (s3vga, s3_lpb_timeout),
s3Get (s3vga, s3_cpu_timeout),
s3Get (s3vga, s3_2d_graphics_engine_timeout));
/*
* Test:
* accel x11perf -line500
* cpu x11perf -circle500
*
* cpu accel
* 1600x1200x32x85 (918000) 1 1 not enough
* 1600x1200x32x75 (810000) 3 2
* 1600x1200x32x70 (756000) 4 3
* 1600x1200x32x60 (648000) 6 5
*
* 1280x1024x32x85 (630000) 6 4
* 1280x1024x32x75 (540000) a 6
* 1280x1024x32x60 (432000) 1f a
*
* 1152x900x32x85 (490000) a 6
* 1152x900x32x75 (433000) 1f 8
* 1152x900x32x70 (401000) 1f a
* 1152x900x32x66 (380000) 1f a
*
* 1024x768x32x85 (378000) 1f a
* 1024x768x32x75 (315000) 1f b
* 1024x768x32x70 (300000) 1f b
* 1024x768x32x60 (260000) 1f 12
*
* 800x600x32x85 (225000) 1f 1a
* 800x600x32x72 (200000) 1f 1d
* 800x600x32x75 (198000) 1f 1d
*
* 1600x1200x16x85 (459000) 1f 8
* 1600x1200x16x75 (405000) 1f a
* 1600x1200x16x70 (378000) 1f b
* 1600x1200x16x60 (324000) 1f f
*
* 1280x1024x16x85 (315000) 1f 12
* 1280x1024x16x75 (270000) 1f 16
* 1280x1024x16x60 (216000) 1f 1d
*
* 1600x1200x8x85 (229000) 1f 1f
*
*/
if (s3CpuTimeout)
{
if (s3CpuTimeout < 0)
cpu_timeout = 0;
else
cpu_timeout = s3CpuTimeout;
if (s3AccelTimeout < 0)
accel_timeout = 0;
else if (s3AccelTimeout)
accel_timeout = s3AccelTimeout;
else
accel_timeout = s3CpuTimeout;
}
else if (bytes_per_ms >= 900000)
{
cpu_timeout = 0x01;
accel_timeout = 0x01;
}
else if (bytes_per_ms >= 800000)
{
cpu_timeout = 0x03;
accel_timeout = 0x02;
}
else if (bytes_per_ms >= 700000)
{
cpu_timeout = 0x04;
accel_timeout = 0x03;
}
else if (bytes_per_ms >= 600000)
{
cpu_timeout = 0x06;
accel_timeout = 0x04;
}
else if (bytes_per_ms >= 475000)
{
cpu_timeout = 0x0a;
accel_timeout = 0x06;
}
else if (bytes_per_ms >= 425000)
{
cpu_timeout = 0x1f;
accel_timeout = 0x8;
}
else if (bytes_per_ms >= 300000)
{
cpu_timeout = 0x1f;
accel_timeout = 0x0a;
}
else if (bytes_per_ms >= 250000)
{
cpu_timeout = 0x1f;
accel_timeout = 0x12;
}
else if (bytes_per_ms >= 200000)
{
cpu_timeout = 0x1f;
accel_timeout = 0x1a;
}
else
{
cpu_timeout = 0x1f;
accel_timeout = 0x1f;
}
fprintf (stderr, "cpu 0x%x accel 0x%x\n", cpu_timeout, accel_timeout);
s3Set (s3vga, s3_primary_stream_timeout, 0xc0);
s3Set (s3vga, s3_master_control_unit_timeout, 0xf);
s3Set (s3vga, s3_command_buffer_timeout, 0x1f);
s3Set (s3vga, s3_lpb_timeout, 0xf);
s3Set (s3vga, s3_2d_graphics_engine_timeout, accel_timeout);
s3Set (s3vga, s3_cpu_timeout, cpu_timeout);
s3Set (s3vga, s3_fifo_fetch_timing, 1);
s3Set (s3vga, s3_fifo_drain_delay, 2);
/*
* Compute horizontal register values from timings
*/
h_total = hactive + hblank - 5;
h_display_end = hactive - 1;
h_sync_start = hactive + hfp + h_sync_start_adjust;
h_sync_end = hactive + hblank - hbp + h_sync_end_adjust;
/*
* pad the blank values narrow a bit and use the border_select to
* eliminate the remaining border; don't know why, but it doesn't
* work in the documented fashion
*/
h_blank_start = hactive + 1 + h_blank_start_adjust;
h_blank_end = hactive + hblank - 2 + h_blank_end_adjust;
/*
* The manual says h_total - 5, but the
* bios does differently...
*/
if (screen->width >= 1600)
h_start_fifo_fetch = h_total - 24;
else if (screen->width >= 1280)
h_start_fifo_fetch = h_total - 19;
else if (screen->width >= 1024)
h_start_fifo_fetch = h_total - 14;
else if (screen->width >= 800)
h_start_fifo_fetch = h_total - 10;
else
h_start_fifo_fetch = h_total - 5;
h_start_fifo_fetch += h_start_fifo_fetch_adjust;
if (h_blank_end - h_blank_start >= 0x40)
h_blank_extend = 1;
else
h_blank_extend = 0;
if (h_sync_end - h_sync_start >= 0x20)
h_sync_extend = 1;
else
h_sync_extend = 0;
#ifdef DEBUG
fprintf (stderr, "h_total %d h_display_end %d\n",
h_total, h_display_end);
fprintf (stderr, "h_sync_start %d h_sync_end %d h_sync_extend %d\n",
h_sync_start, h_sync_end, h_sync_extend);
fprintf (stderr, "h_blank_start %d h_blank_end %d h_blank_extend %d\n",
h_blank_start, h_blank_end, h_blank_extend);
#endif
s3Set (s3vga, s3_h_total, h_total);
s3Set (s3vga, s3_h_display_end, h_display_end);
s3Set (s3vga, s3_h_blank_start, h_blank_start);
s3Set (s3vga, s3_h_blank_end, h_blank_end);
s3Set (s3vga, s3_h_sync_start, h_sync_start);
s3Set (s3vga, s3_h_sync_end, h_sync_end);
s3Set (s3vga, s3_screen_offset, h_screen_off);
s3Set (s3vga, s3_h_start_fifo_fetch, h_start_fifo_fetch);
s3Set (s3vga, s3_h_sync_extend, h_sync_extend);
s3Set (s3vga, s3_h_blank_extend, h_blank_extend);
s3Set (s3vga, s3_dac_power_saving_disable, 0);
s3Set (s3vga, s3_dac_power_up_time, hactive + hblank);
s3Set (s3vga, s3_primary_stream_l1, primary_stream_l1[0]);
s3Set (s3vga, s3_streams_fifo_delay, 0);
v_total = vactive + vblank - 2;
v_display_end = vactive - 1;
v_blank_start = vactive - 1 + v_blank_start_adjust;
v_blank_end = v_blank_start + vblank - 1 + v_blank_end_adjust;
v_retrace_start = vactive + vfp;
v_retrace_end = vactive + vblank - vbp;
s3Set (s3vga, s3_v_total, v_total);
s3Set (s3vga, s3_v_retrace_start, v_retrace_start);
s3Set (s3vga, s3_v_retrace_end, v_retrace_end);
s3Set (s3vga, s3_v_display_end, v_display_end);
s3Set (s3vga, s3_v_blank_start, v_blank_start);
s3Set (s3vga, s3_v_blank_end, v_blank_end);
if (vactive >= 1024)
s3Set (s3vga, s3_line_compare, 0x7ff);
else
s3Set (s3vga, s3_line_compare, 0x3ff);
/*
* Set cursor
*/
if (!screen->softCursor)
{
cursor_address = (s3s->cursor_base - s3c->frameBuffer) / 1024;
s3Set (s3vga, s3_cursor_address, cursor_address);
s3Set (s3vga, s3_cursor_ms_x11, 0);
s3Set (s3vga, s3_cursor_enable, 1);
}
else
s3Set (s3vga, s3_cursor_enable, 0);
#define MAKE_GBF(bds,be,stride,bpp,tile) (\
((bds) << 0) | \
((be) << 3) | \
((stride) << 4) | \
((bpp) << 16) | \
((tile) << 24))
/*
* Set accelerator
*/
switch (screen->width) {
#if 0
case 640: s3Set (s3vga, s3_ge_screen_width, 1); break;
case 800: s3Set (s3vga, s3_ge_screen_width, 2); break;
case 1024: s3Set (s3vga, s3_ge_screen_width, 0); break;
case 1152: s3Set (s3vga, s3_ge_screen_width, 4); break;
case 1280: s3Set (s3vga, s3_ge_screen_width, 3); break;
case 1600: s3Set (s3vga, s3_ge_screen_width, 6); break;
#endif
default:
s3Set (s3vga, s3_ge_screen_width, 7); /* use global bitmap descriptor */
}
#if 0
crtc->l_parm_0_7 = screen->width / 4; /* Undocumented. */
#endif
/*
* Set DPMS to normal
*/
s3Set (s3vga, s3_hsync_control, 0);
s3Set (s3vga, s3_vsync_control, 0);
_s3SetBlank (s3, s3vga, TRUE);
if (s3s->use_streams)
s3Set (s3vga, s3_primary_stream_definition, 1);
else
s3Set (s3vga, s3_primary_stream_definition, 0);
VgaFlush(&s3vga->card);
VgaSetImm (&s3vga->card, s3_clock_load_imm, 1);
VgaSetImm(&s3vga->card, s3_clock_load_imm, 0);
if (s3s->use_streams)
{
fb = s3s->fbmap[0];
s3->primary_stream_control = control[0];
s3->primary_stream_addr_0 =
s3->primary_stream_addr_1 = s3s->fb[0].bitmap_offset;
s3->primary_stream_stride = screen->fb[fb].byteStride;
s3->primary_stream_xy = (1 << 16) | 1;
s3->primary_stream_size = ((screen->fb[fb].pixelStride - 1) << 16) | screen->height;
s3->primary_stream_mem = (screen->fb[fb].byteStride * screen->height) / 8 - 1;
if (s3s->fbmap[1] >= 0)
{
fb = s3s->fbmap[1];
s3->blend_control = 5 << 24;
if (s3s->fb[0].accel_bpp == 8)
s3->chroma_key_control = 0x33000000 | s3s->fb[0].chroma_key;
else
s3->chroma_key_control = 0x13010101;
s3->secondary_stream_control = control[1] | screen->width;
s3->secondary_stream_h_scale = (1 << 15);
s3->color_adjustment = 0;
s3->secondary_stream_vscale = (1 << 15);
s3->secondary_stream_vinit = 0;
s3->secondary_stream_mbuf = 0;
s3->secondary_stream_addr_0 =
s3->secondary_stream_addr_1 = s3s->fb[1].bitmap_offset;
s3->secondary_stream_stride = screen->fb[fb].byteStride;
s3->secondary_stream_scount = screen->height;
s3->secondary_stream_xy = (1 << 16) | 1;
s3->secondary_stream_size = ((screen->fb[fb].pixelStride - 1) << 16) | screen->height;
s3->secondary_stream_mem = (1 << 22) | ((screen->fb[fb].byteStride * screen->height) / 8 - 1);
}
else
{
s3->blend_control = 1 << 24;
s3->secondary_stream_xy = 0x07ff07ff;
s3->secondary_stream_size = 0x00010001;
}
s3->streams_fifo = (0x20 << 11) | (0x20 << 5) | 0x2;
}
s3->mult_misc_read_sel = (((1 << 9) |
(1 << 11) |
(0xe << 12)) |
(((0xe << 0) |
(0xf << 12)) << 16));
s3->cmd_overflow_buf_ptr = (1 << 3);
s3->bci_power_management = (1 << 9);
s3->adv_func_cntl = (3 << 8) | (1 << 4) | (1 << 2) | 1;
s3->primary_bitmap_1 = 0;
s3->primary_bitmap_2 = 0;
s3->secondary_bitmap_1 = 0;
s3->secondary_bitmap_2 = 0;
s3s->current_ma = -1;
_s3SetBlank (s3, s3vga, FALSE);
#if 0
{
VGA16 r;
static CARD32 streams[][2] = {
/* PCI registers */
0x8000, 0x8024,
0x802c, 0x8034,
0x803c, 0x8040,
#if 0
0x8080, 0x808c, /* AGP */
#endif
0x80dc, 0x80e0,
/* 2D registers */
0x8168, 0x8188,
0x8190, 0x81a0,
0x81c0, 0x81d8,
0x81e0, 0x8218,
0x8300, 0x8308,
0x8504, 0x8510,
/* LPB/VIP registers */
0xff00, 0xff18,
0xff20, 0xff38,
0xff40, 0xff40,
0xff70, 0xff78,
0xff8c, 0xffa0,
#if 0
/* 3D registers */
0x48508, 0x48508,
0x48528, 0x48528,
0x48548, 0x48548,
0x48584, 0x485f0,
#endif
/* motion compensation registers */
0x48900, 0x48924,
#if 0
0x48928, 0x48928,
#endif
/* Mastered data transfer registers */
0x48a00, 0x48a1c,
/* configuation/status registers */
0x48c00, 0x48c18,
0x48c20, 0x48c24,
0x48c40, 0x48c50,
0x48c60, 0x48c64,
0, 0,
};
#ifdef PHOENIX
#undef stderr
#define stderr stdout
#endif
CARD32 *regs = (CARD32 *) s3c->registers;
int i;
CARD32 reg;
for (r = S3_SR + 0; r < S3_SR + S3_NSR; r++)
fprintf (stderr, "SR%02x = %02x\n", r-S3_SR, VgaFetch (&s3vga->card, r));
for (r = S3_GR + 0; r < S3_GR + S3_NGR; r++)
fprintf (stderr, "GR%02x = %02x\n", r-S3_GR, VgaFetch (&s3vga->card, r));
for (r = S3_AR + 0; r < S3_AR + S3_NAR; r++)
fprintf (stderr, "AR%02x = %02x\n", r-S3_AR, VgaFetch (&s3vga->card, r));
for (r = S3_CR + 0; r < S3_CR + S3_NCR; r++)
fprintf (stderr, "CR%02x = %02x\n", r-S3_CR, VgaFetch (&s3vga->card, r));
for (r = S3_DAC + 0; r < S3_DAC + S3_NDAC; r++)
fprintf (stderr, "DAC%02x = %02x\n", r-S3_DAC, VgaFetch (&s3vga->card, r));
fprintf (stderr, "MISC_OUT = %02x\n", VgaFetch (&s3vga->card, S3_MISC_OUT));
fprintf (stderr, "INPUT_STATUS = %02x\n", VgaFetch (&s3vga->card, S3_INPUT_STATUS_1));
for (i = 0; streams[i][0]; i++)
{
for (reg = streams[i][0]; reg <= streams[i][1]; reg += 4)
fprintf (stderr, "0x%4x: 0x%08x\n", reg, regs[reg/4]);
}
}
#endif
return TRUE;
}
void
s3Disable (ScreenPtr pScreen)
{
}
void
s3Restore (KdCardInfo *card)
{
S3CardInfo *s3c = card->driver;
S3Ptr s3 = s3c->s3;
S3Vga *s3vga = &s3c->s3vga;
S3Save *save = &s3c->save;
CARD8 *cursor_base;
CARD8 streams_mode;
_s3SetBlank (s3, s3vga, TRUE);
/* streams processor state */
streams_mode = s3Get (s3vga, s3_streams_mode);
s3SetImm (s3vga, s3_streams_mode, 3);
s3->global_bitmap_1 = save->global_bitmap_1;
s3->global_bitmap_2 = save->global_bitmap_2;
s3->adv_func_cntl = save->adv_func_cntl;
s3->primary_bitmap_1 = save->primary_bitmap_1;
s3->primary_bitmap_2 = save->primary_bitmap_2;
s3->secondary_bitmap_1 = save->secondary_bitmap_1;
s3->secondary_bitmap_2 = save->secondary_bitmap_2;
s3->primary_stream_control = save->primary_stream_control;
s3->blend_control = save->blend_control;
s3->primary_stream_addr_0 = save->primary_stream_addr_0;
s3->primary_stream_addr_0 = save->primary_stream_addr_0;
s3->primary_stream_stride = save->primary_stream_stride;
s3->primary_stream_xy = save->primary_stream_xy;
s3->primary_stream_size = save->primary_stream_size;
s3->primary_stream_mem = save->primary_stream_mem;
s3->secondary_stream_xy = save->secondary_stream_xy;
s3->secondary_stream_size = save->secondary_stream_size;
s3->streams_fifo = save->streams_fifo;
s3SetImm (s3vga, s3_streams_mode, streams_mode);
/* graphics engine state */
s3->alt_mix = save->alt_mix;
s3->write_mask = save->write_mask;
s3->fg = save->fg;
s3->bg = save->bg;
/* XXX should save and restore real values? */
s3->scissors_tl = 0x00000000;
s3->scissors_br = 0x0fff0fff;
VgaRestore (&s3vga->card);
s3Set (s3vga, s3_linear_window_size, 3);
s3Set (s3vga, s3_enable_linear, 1);
VgaFlush (&s3vga->card);
memcpy (s3c->frameBuffer, save->text_save, S3_TEXT_SAVE);
s3Reset (s3vga);
_s3SetBlank (s3, s3vga, FALSE);
}
void
_s3SetSync (S3CardInfo *s3c, int hsync, int vsync)
{
/* this abuses the macros defined to access the crtc structure */
S3Ptr s3 = s3c->s3;
S3Vga *s3vga = &s3c->s3vga;
s3Set (s3vga, s3_hsync_control, hsync);
s3Set (s3vga, s3_vsync_control, vsync);
VgaFlush (&s3vga->card);
}
Bool
s3DPMS (ScreenPtr pScreen, int mode)
{
KdScreenPriv(pScreen);
s3CardInfo(pScreenPriv);
S3Vga *s3vga = &s3c->s3vga;
switch (mode) {
case KD_DPMS_NORMAL:
_s3SetSync (s3c, 0, 0);
_s3SetBlank (s3c->s3, s3vga, FALSE);
break;
case KD_DPMS_STANDBY:
_s3SetBlank (s3c->s3, s3vga, TRUE);
_s3SetSync (s3c, 1, 0);
break;
case KD_DPMS_SUSPEND:
_s3SetBlank (s3c->s3, s3vga, TRUE);
_s3SetSync (s3c, 0, 1);
break;
case KD_DPMS_POWERDOWN:
_s3SetBlank (s3c->s3, s3vga, TRUE);
_s3SetSync (s3c, 1, 1);
break;
}
return TRUE;
}
Bool
s3InitScreen(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
KdCardInfo *card = pScreenPriv->card;
KdScreenInfo *screen = pScreenPriv->screen;
s3CardInfo (pScreenPriv);
s3ScreenInfo (pScreenPriv);
int ma, fb;
if (screen->fb[1].depth)
{
FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
{
fb = s3s->fbmap[ma];
pScrPriv->layer[fb].key = s3s->fb[ma].chroma_key;
}
}
return TRUE;
}
void
s3ScreenFini (KdScreenInfo *screen)
{
S3ScreenInfo *s3s = (S3ScreenInfo *) screen->driver;
xfree (s3s);
screen->driver = 0;
}
void
s3CardFini (KdCardInfo *card)
{
S3CardInfo *s3c = (S3CardInfo *) card->driver;
KdUnmapDevice (s3c->frameBuffer, s3c->memory);
KdUnmapDevice (s3c->registers, sizeof (S3) + PACKED_OFFSET);
xfree (s3c);
card->driver = 0;
}
KdCardFuncs s3Funcs = {
s3CardInit,
s3ScreenInit,
s3InitScreen,
s3Preserve,
s3Enable,
s3DPMS,
s3Disable,
s3Restore,
s3ScreenFini,
s3CardFini,
s3CursorInit,
s3CursorEnable,
s3CursorDisable,
s3CursorFini,
s3RecolorCursor,
s3DrawInit,
s3DrawEnable,
s3DrawSync,
s3DrawDisable,
s3DrawFini,
s3GetColors,
s3PutColors,
};