/*
* VGAlib version 1.2 - (c) 1993 Tommy Frandsen
*
* This library is free software; you can redistribute it and/or
* modify it without any restrictions. This library is distributed
* in the hope that it will be useful, but without any warranty.
*
* Multi-chipset support Copyright (C) 1993 Harm Hanemaayer
* S3 805,868 support Copyright (C) 1995 Stephen Lee
*/
/*
* Mar 1999 (Eduardo ...)
* Recognizes Trio3D as Trio64
*
* Sep 1997 (Greg Alexander):
* Recognizes S3Trio64V2/DX cards as Trio64's.
*
* Feb 1996 (Stephen Lee):
* 968/IBMRGB support. Only 256 colors for now.
* can now save more than 10 DAC registers (IBMRGB has 256!)
* Trio64 patch from Moto Kawamura <kawamura@mmp.cl.nec.co.jp>.
* Changed handling of CR34 for VGA modes at Andreas' suggestion.
* Changes to s3_saveregs() and s3_setregs() to make them more safe against
* lockups.
* 16 color mode should work on the 868/SDAC.
* SDAC 4/8bpp doesn't seem to do pixel multiplexing.
*
* Dec 1995 (Stephen Lee):
* Fixed color problem with 868 (CR43 again!). Could somebody find the
* value that works with Trio64?
*
* Nov 1995 (Stephen Lee):
* Linear addressing mode partially works (but is very alpha).
* Merged in Andreas Arens' <ari@av.rwth-aachen.de> patch for the 928.
*
* Sep 1995 (Stephen Lee):
* 16 Colors works on my 805, should work on other cards too.
*
* Alternate banking scheme for 864+. If you have problems, try undefining
* S3_LINEAR_MODE_BANKING_864.
*
* 8 bit color *really* works. Took me 3 months to bag this sucker.
*
* SVGA 8 bit color modes works. 320x200x256 is not really 'packed-pixel',
* it occupies 256K per page. There is no SVGA 320x200x256 mode; I cannot
* get the display (timing?) right.
*
* Aug 1995 (Stephen Lee):
* Added "Dacspeed" parsing.
* Added support for CLUT8_8 on ATT20C490/498.
* Improved support for S3-801/805.
* 15/16/24 bit colors works on the 805 + ATT20C490 I tested.
* Newer chipsets are recognized (but no support coded in yet).
* Should recognize memory size correctly on S3-924.
*
* Dec 1994 (Harm Hanemaayer):
* Partially rewritten using new SVGA-abstracted interface.
* Based on XFree86 code (accel/s3/s3.c and s3init.c).
* Goal is to have support for the S3-864 + S3-SDAC (which I can test).
* 80x with GENDAC might also be supported.
* Also, 640x480x256 should work on cards that have standard 25 and 28 MHz
* clocks.
*
* XFree86-equivalent clock select is now supported plus some
* industry-standard RAMDACs.
*
* Remaining problems:
* * Okay, okay, so 256 color still isn't fully working on the 805. I'm
* trying to get a fix for it.
*
* * The DCLK limit for 864/868 is a bit too relaxed. If you see noise at
* the highest resolutions when the screen is drawing it is possibly due
* to this. (How about changing MCLK?)
*
* * Horizontal Total is limited to 4088 which makes some modes unavailable
* (e.g. 800x600x16M with HTotal > 1022). Should experiment with
* CR43.7?
*
* * Some 864 problems are now fixed -- XF86_S3 seems to program the
* linewidth in bytes doubled for the S3-864 with > 1024K, which
* caused problems for this driver. There's still interference
* though when writing to video memory in the higher resolutions.
*
* * XXXX results of malloc() are not checked: should fix sometime.
*/
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "vga.h"
#include "libvga.h"
#include "driver.h"
#include "timing.h"
#include "ramdac.h"
#include "clockchip.h"
#include "vgaregs.h"
#include "interface.h"
#include "8514a.h"
#include "vgapci.h"
/* no acceleration as of now. */
#undef S3_USE_GRAPHIC_ENGINE
/* kludge packed pixel for 320x200x256 */
/* XXXX doesn't really work */
#undef S3_KLUDGE_PAGE_MODE
/* use alternate 'linear' banking method for 864+ */
#undef S3_LINEAR_MODE_BANKING_864
#ifdef __alpha__ /* no good for alpha's */
#undef S3_LINEAR_MODE_BANKING_864
#endif
/*
* supports linear buffer.
*
* XXXX does not work with console switching and might be incompatible with
* S3_LINEAR_MODE_BANKING_864.
*/
#define S3_LINEAR_SUPPORT
/* supports 16 colors */
#define S3_16_COLORS
/*
* zero wait state + (ramdac?) FIFO for 864 & 805,
* twice as fast but might not work on some cards.
*/
#undef S3_0_WAIT_805_864
enum {
S3_911
, S3_924
, S3_801
, S3_805
, S3_928
, S3_864
, S3_964
, S3_TRIO32
,
S3_TRIO64
, S3_866
, S3_868
, S3_968
, S3_765
};
static const char *s3_chipname
[] =
{"911", "924", "801", "805", "928",
"864", "964", "Trio32", "Trio64", "866", "868", "968", "Trio64V+"};
#define S3_CR(n) (EXT + (0x##n) - 0x30)
#define S3_CR30 S3_CR(30)
#define S3_CR31 S3_CR(31)
#define S3_CR32 S3_CR(32)
#define S3_CR33 S3_CR(33)
#define S3_CR34 S3_CR(34)
#define S3_CR35 S3_CR(35)
#define S3_CR3A S3_CR(3A)
#define S3_CR3B S3_CR(3B)
#define S3_CR3C S3_CR(3C)
#define S3_CR40 S3_CR(40)
#define S3_CR42 S3_CR(42)
#define S3_CR43 S3_CR(43)
#define S3_CR44 S3_CR(44)
#define S3_CR50 S3_CR(50) /* 801+ */
#define S3_CR51 S3_CR(51)
#define S3_CR53 S3_CR(53)
#define S3_CR54 S3_CR(54)
#define S3_CR55 S3_CR(55)
#define S3_CR58 S3_CR(58)
#define S3_CR59 S3_CR(59)
#define S3_CR5A S3_CR(5A)
#define S3_CR5D S3_CR(5D)
#define S3_CR5E S3_CR(5E)
#define S3_CR60 S3_CR(60)
#define S3_CR61 S3_CR(61)
#define S3_CR62 S3_CR(62)
#define S3_CR67 S3_CR(67)
#define S3_CR6A S3_CR(6A)
#define S3_CR6D S3_CR(6D)
/* For debugging, these (non-)registers are read also (but never written). */
#define S3_CR36 S3_CR(36)
#define S3_CR37 S3_CR(37)
#define S3_CR38 S3_CR(38)
#define S3_CR39 S3_CR(39)
#define S3_CR3D S3_CR(3D)
#define S3_CR3E S3_CR(3E)
#define S3_CR3F S3_CR(3F)
#define S3_CR45 S3_CR(45)
#define S3_CR46 S3_CR(46)
#define S3_CR47 S3_CR(47)
#define S3_CR48 S3_CR(48)
#define S3_CR49 S3_CR(49)
#define S3_CR4A S3_CR(4A)
#define S3_CR4B S3_CR(4B)
#define S3_CR4C S3_CR(4C)
#define S3_CR4D S3_CR(4D)
#define S3_CR4E S3_CR(4E)
#define S3_CR4F S3_CR(4F)
#define S3_CR52 S3_CR(52)
#define S3_CR56 S3_CR(56)
#define S3_CR57 S3_CR(57)
#define S3_CR5B S3_CR(5B)
#define S3_CR5C S3_CR(5C)
#define S3_CR5F S3_CR(5F)
#define S3_CR63 S3_CR(63)
#define S3_CR64 S3_CR(64)
#define S3_CR65 S3_CR(65)
#define S3_CR66 S3_CR(66)
#define S3_CR6E S3_CR(6E)
#define S3_CR6F S3_CR(6F)
/* Trio extended SR registers */
#define S3_SR(n) (S3_CR6F + 1 + (0x##n) - 0x08)
#define S3_SR08 S3_SR(08)
#define S3_SR09 S3_SR(09)
#define S3_SR0A S3_SR(0A)
#define S3_SR0D S3_SR(0D)
#define S3_SR10 S3_SR(10)
#define S3_SR11 S3_SR(11)
#define S3_SR12 S3_SR(12)
#define S3_SR13 S3_SR(13)
#define S3_SR15 S3_SR(15)
#define S3_SR18 S3_SR(18)
#define S3_SR1D S3_SR(1D)
#define S3_8514_OFFSET (S3_SR1D + 1)
#define S3_8514_COUNT (1) /* number of 2-byte words */
#define S3_DAC_OFFSET (S3_8514_OFFSET + (S3_8514_COUNT * 2))
#define S3_TOTAL_REGS (S3_DAC_OFFSET + MAX_DAC_STATE)
/* 8514 regs */
#define S3_ADVFUNC_CNTL 0
static unsigned short s3_8514regs
[S3_8514_COUNT
] =
{
/* default assuming text mode */
0x0000U
};
/* flags used by this driver */
#define S3_LOCALBUS 0x01
#define S3_CLUT8_8 0x02
#define S3_OLD_STEPPING 0x04
static int s3_flags
= 0;
static int s3_chiptype
;
static int s3_memory
;
static CardSpecs
*cardspecs
;
static DacMethods
*dac_used
;
static ClockChipMethods
*clk_used
;
static int dac_speed
= 0;
int __svgalib_s3_s3Mclk
= 0;
/* forward declaration. */
extern DriverSpecs __svgalib_s3_driverspecs
;
static int s3_init
(int, int, int);
static void s3_setpage
(int page
);
#ifdef S3_LINEAR_MODE_BANKING_864
static void s3_setpage864
(int page
);
#endif
#ifdef S3_LINEAR_SUPPORT
static int s3_cr40
;
static int s3_cr54
;
static int s3_cr58
;
static int s3_cr59
;
static int s3_cr5A
;
static int s3_linear_opt
= 0;
static int s3_linear_addr
= 0;
static int s3_linear_base
= 0;
static void s3_linear_enable
(void);
static void s3_linear_disable
(void);
#endif
static void nothing
(void)
{
}
/*
* Lock S3's registers.
* There are more locks, but this should suffice.
*
* ARI: More complete Extended VGA Register Lock Documentation, as of Ferraro:
*
* Register Bit Controls Access To: Function
* CR33 1 CR7 bits 1 and 6 1=disable write protect
* setting of CR11 bit 7
* CR33 4 Ramdac Register 1=disable writes
* CR33 6 Palette/Overscan Registers 1=lock
* CR34 5 Memory Configuration bit 5 1=lock
* CR34 7 Misc Register bit 3-2 (Clock) 1=lock
* CR35 4 Vertical Timing Registers 1=lock
* CR35 5 Horizontal Timing Registers 1=lock
*
* XXXX mostly, need to lock the enhanced command regs on the 805 (and
* probably below) to avoid display corruption.
*/
static void s3_lock
(void)
{
__svgalib_outCR
(0x39, 0x00); /* Lock system control regs. */
__svgalib_outCR
(0x38, 0x00); /* Lock special regs. */
}
static void s3_lock_enh
(void)
{
if (s3_chiptype
> S3_911
)
__svgalib_outCR
(0x40, __svgalib_inCR
(0x40) & ~
0x01); /* Lock enhanced command regs. */
s3_lock
();
}
/*
* Unlock S3's registers.
* There are more locks, but this should suffice.
*/
static void s3_unlock
(void)
{
__svgalib_outCR
(0x38, 0x48); /* Unlock special regs. */
__svgalib_outCR
(0x39, 0xA5); /* Unlock system control regs. */
}
static void s3_unlock_enh
(void)
{
s3_unlock
();
if (s3_chiptype
> S3_911
)
__svgalib_outCR
(0x40, __svgalib_inCR
(0x40) | 0x01); /* Unlock enhanced command regs. */
}
/*
* Adjust the display width. This is necessary for the graphics
* engine if acceleration is used. However it will require more
* memory making some modes unavailable.
*/
static int s3_adjlinewidth
(int oldwidth
)
{
if (s3_chiptype
< S3_801
)
return 1024;
#ifdef S3_USE_GRAPHIC_ENGINE
if (oldwidth
<= 640)
return 640;
if (oldwidth
<= 800)
return 800;
if (oldwidth
<= 1024)
return 1024;
if (!(s3_flags
& S3_OLD_STEPPING
))
if (oldwidth
<= 1152)
return 1152;
if (oldwidth
<= 1280)
return 1280;
if (oldwidth
<= 1600 && s3_chiptype
>= S3_864
)
return 1600;
return 2048;
#else
return oldwidth
;
#endif
}
/* Fill in chipset specific mode information */
static void s3_getmodeinfo
(int mode
, vga_modeinfo
* modeinfo
)
{
switch (modeinfo
->colors
) {
case 16: /* 4-plane 16 color mode */
modeinfo
->maxpixels
= s3_memory
* 1024 * 2;
break;
default:
modeinfo
->maxpixels
= s3_memory
* 1024 /
modeinfo
->bytesperpixel
;
}
/* Adjust line width (only for SVGA modes) */
if (!IS_IN_STANDARD_VGA_DRIVER
(mode
))
modeinfo
->linewidth
= s3_adjlinewidth
(modeinfo
->linewidth
);
modeinfo
->maxlogicalwidth
= 8184;
if (s3_chiptype
>= S3_801
)
modeinfo
->startaddressrange
= 0x3fffff;
else
modeinfo
->startaddressrange
= 0xfffff;
#ifdef S3_KLUDGE_PAGE_MODE
if (mode
== G320x200x256
) {
/* set page size to 256k. */
modeinfo
->startaddressrange
/= 4;
modeinfo
->maxpixels
/= 4;
}
#else
if (mode
== G320x200x256
) {
/* disable page flipping. */
/* modeinfo->startaddressrange = 0xffff; */
modeinfo
->startaddressrange
= 0;
modeinfo
->maxpixels
= 65536;
}
#endif
modeinfo
->haveblit
= 0;
modeinfo
->flags
&= ~HAVE_RWPAGE
;
modeinfo
->flags
|= HAVE_EXT_SET
;
#ifdef S3_LINEAR_SUPPORT
if (modeinfo
->bytesperpixel
>= 1) {
modeinfo
->flags
|= CAPABLE_LINEAR
;
if (s3_linear_addr
)
modeinfo
->flags
|= IS_LINEAR
| LINEAR_MODE
;
}
#endif
modeinfo
->memory
= s3_memory
;
modeinfo
->chiptype
= s3_chiptype
;
}
/*
* XXX Part of this function should be implemented in ramdac.c,
* but we just kludge it here for now.
*/
static int s3_ext_set
(unsigned what
, va_list params
)
{
int param2
, old_values
;
unsigned char regs
[10];
/* only know this, for now */
if (dac_used
->id
!= ATT20C490
&& dac_used
->id
!= ATT20C498
&&
dac_used
->id
!= SIERRA_15025
)
return 0;
param2
= va_arg(params
, int);
old_values
= (s3_flags
& S3_CLUT8_8
) ? VGA_CLUT8
: 0;
switch (what
) {
case VGA_EXT_AVAILABLE
:
switch (param2
) {
case VGA_AVAIL_SET
:
return VGA_EXT_AVAILABLE
| VGA_EXT_SET
| VGA_EXT_CLEAR
| VGA_EXT_RESET
;
case VGA_AVAIL_ACCEL
:
return 0;
case VGA_AVAIL_FLAGS
:
return VGA_CLUT8
;
}
break;
case VGA_EXT_SET
:
if (param2
& VGA_CLUT8
)
goto setclut8
;
case VGA_EXT_CLEAR
:
if (param2
& VGA_CLUT8
)
goto clearclut8
;
case VGA_EXT_RESET
:
if (param2
& VGA_CLUT8
) {
setclut8
:
dac_used
->saveState
(regs
);
if (regs
[0] == 0x00) { /* 8bpp, 6 bits/color */
s3_flags
|= S3_CLUT8_8
;
if (dac_used
->id
== SIERRA_15025
)
regs
[1] = 1;
regs
[0] = 0x02;
}
dac_used
->restoreState
(regs
);
return old_values
;
} else {
clearclut8
:
dac_used
->saveState
(regs
);
if (regs
[0] == 0x02) { /* 8bpp, 8 bits/color */
s3_flags
&= ~S3_CLUT8_8
;
if (dac_used
->id
== SIERRA_15025
)
regs
[1] = 0;
regs
[0] = 0x00;
}
dac_used
->restoreState
(regs
);
return old_values
;
}
default:
break;
}
return 0;
}
/* Return non-zero if mode is available */
static int s3_modeavailable
(int mode
)
{
struct info
*info
;
ModeInfo
*modeinfo
;
ModeTiming
*modetiming
;
if (IS_IN_STANDARD_VGA_DRIVER
(mode
))
return __svgalib_vga_driverspecs.
modeavailable(mode
);
/* Enough memory? */
info
= &__svgalib_infotable
[mode
];
if (s3_memory
* 1024 < info
->ydim
* s3_adjlinewidth
(info
->xbytes
))
return 0;
modeinfo
= __svgalib_createModeInfoStructureForSvgalibMode
(mode
);
modetiming
= malloc(sizeof(ModeTiming
));
if (__svgalib_getmodetiming
(modetiming
, modeinfo
, cardspecs
)) {
free(modetiming
);
free(modeinfo
);
return 0;
}
free(modetiming
);
free(modeinfo
);
return SVGADRV
;
}
/*
* save S3 registers. Lock registers receive special treatment
* so dumpreg will work under X.
*/
static int s3_saveregs
(unsigned char regs
[])
{
unsigned char b
, bmax
;
unsigned char cr38
, cr39
, cr40
;
cr38
= __svgalib_inCR
(0x38);
__svgalib_outCR
(0x38, 0x48); /* unlock S3 VGA regs (CR30-CR3B) */
cr39
= __svgalib_inCR
(0x39);
__svgalib_outCR
(0x39, 0xA5); /* unlock S3 system control (CR40-CR4F) */
/* and extended regs (CR50-CR6D) */
cr40
= __svgalib_inCR
(0x40); /* unlock enhanced regs */
__svgalib_outCR
(0x40, cr40
| 0x01);
/* retrieve values from private copy */
memcpy(regs
+ S3_8514_OFFSET
, s3_8514regs
, S3_8514_COUNT
* 2);
/* get S3 VGA/Ext registers */
bmax
= 0x4F;
if (s3_chiptype
>= S3_801
)
bmax
= 0x66;
if (s3_chiptype
>= S3_864
)
bmax
= 0x6D;
for (b
= 0x30; b
<= bmax
; b
++)
regs
[EXT
+ b
- 0x30] = __svgalib_inCR
(b
);
/* get S3 ext. SR registers */
/* if (s3_chiptype >= S3_864) { */
if (s3_chiptype
== S3_TRIO32
|| s3_chiptype
== S3_TRIO64
|| s3_chiptype
== S3_765
) {/* SL: actually Trio32/64/V+ */
regs
[S3_SR08
] = __svgalib_inSR
(0x08);
__svgalib_outSR
(0x08, 0x06); /* unlock extended seq regs */
regs
[S3_SR09
] = __svgalib_inSR
(0x09);
regs
[S3_SR0A
] = __svgalib_inSR
(0x0A);
regs
[S3_SR0D
] = __svgalib_inSR
(0x0D);
regs
[S3_SR10
] = __svgalib_inSR
(0x10);
regs
[S3_SR11
] = __svgalib_inSR
(0x11);
regs
[S3_SR12
] = __svgalib_inSR
(0x12);
regs
[S3_SR13
] = __svgalib_inSR
(0x13);
regs
[S3_SR15
] = __svgalib_inSR
(0x15);
regs
[S3_SR18
] = __svgalib_inSR
(0x18);
__svgalib_outSR
(0x08, regs
[S3_SR08
]);
}
dac_used
->saveState
(regs
+ S3_DAC_OFFSET
);
/* leave the locks the way we found it */
__svgalib_outCR
(0x40, regs
[EXT
+ 0x40 - 0x30] = cr40
);
__svgalib_outCR
(0x39, regs
[EXT
+ 0x39 - 0x30] = cr39
);
__svgalib_outCR
(0x38, regs
[EXT
+ 0x38 - 0x30] = cr38
);
#if 0
#include "ramdac/IBMRGB52x.h"
do {
unsigned char m
, n
, df
;
fprintf(stderr
,"pix_fmt = 0x%02X, 8bpp = 0x%02X, 16bpp = 0x%02X, 24bpp = 0x%02X, 32bpp = 0x%02X,\n"
"CR58 = 0x%02X, CR66 = 0x%02X, CR67 = 0x%02X, CR6D = 0x%02X\n",
regs
[S3_DAC_OFFSET
+ IBMRGB_pix_fmt
],
regs
[S3_DAC_OFFSET
+ IBMRGB_8bpp
],
regs
[S3_DAC_OFFSET
+ IBMRGB_16bpp
],
regs
[S3_DAC_OFFSET
+ IBMRGB_24bpp
],
regs
[S3_DAC_OFFSET
+ IBMRGB_32bpp
],
regs
[S3_CR58
],
regs
[S3_CR66
],
regs
[S3_CR67
],
regs
[S3_CR6D
]);
m
= regs
[S3_DAC_OFFSET
+ IBMRGB_m0
+ 4];
n
= regs
[S3_DAC_OFFSET
+ IBMRGB_n0
+ 4];
df
= m
>> 6;
m
&= ~
0xC0;
fprintf(stderr
,"m = 0x%02X %d, n = 0x%02X %d, df = 0x%02X %d, freq = %.3f\n",
m
, m
, n
, n
, df
, df
, ((m
+ 65.0) / n
) / (8 >> df
) * 16.0);
} while (0);
#endif
return S3_DAC_OFFSET
- VGA_TOTAL_REGS
+ dac_used
->stateSize
;
}
/* Set chipset-specific registers */
static void s3_setregs
(const unsigned char regs
[], int mode
)
{
unsigned char b
, bmax
;
/*
* Right now, anything != 0x00 gets written in s3_setregs.
* May change this into a bitmask later.
*/
static unsigned char s3_regmask
[] =
{
0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x00, 0x00, /* CR30-CR37 */
0x00, 0x00, 0x3A, 0x3B, 0x3C, 0x00, 0x00, 0x00, /* CR38-CR3F */
0x00, 0x00, 0x42, 0x43, 0x44, 0x00, 0x00, 0x00, /* CR40-CR47 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* CR48-CR4F */
0x50, 0x51, 0x00, 0x00, 0x54, 0x55, 0x00, 0x00, /* CR50-CR57 */
0x58, 0x59, 0x5A, 0x00, 0x00, 0x5D, 0x5E, 0x00, /* CR58-CR5F */
0x60, 0x61, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, /* CR60-CR67 */
0x00, 0x00, 0x6A, 0x00, 0x00, 0x00 /* CR68-CR6D */
};
s3_unlock_enh
();
/* save a private copy */
memcpy(s3_8514regs
, regs
+ S3_8514_OFFSET
, S3_8514_COUNT
* 2);
/*
* set this first, so if we segfault on this
* we don't get a screwed up display
*/
outw
(ADVFUNC_CNTL
, s3_8514regs
[S3_ADVFUNC_CNTL
]);
/* get S3 VGA/Ext registers */
bmax
= 0x4F;
if (s3_chiptype
>= S3_801
)
bmax
= 0x66;
if (s3_chiptype
>= S3_864
)
bmax
= 0x6D;
for (b
= 0x30; b
<= bmax
; b
++) {
if (s3_regmask
[b
- 0x30])
__svgalib_outCR
(b
, regs
[EXT
+ b
- 0x30]);
}
if (dac_used
->id
!= NORMAL_DAC
) {
unsigned char CR1
;
/* Blank the screen. */
CR1
= __svgalib_inCR
(0x01);
__svgalib_outCR
(0x01, CR1
| 0x20);
__svgalib_outcrtc
(0x55, __svgalib_inCR
(0x55) | 1);
__svgalib_outcrtc
(0x66, regs
[S3_CR66
]);
__svgalib_outcrtc
(0x67, regs
[S3_CR67
]); /* S3 pixmux. */
dac_used
->restoreState
(regs
+ S3_DAC_OFFSET
);
__svgalib_outcrtc
(0x6D, regs
[S3_CR6D
]);
__svgalib_outcrtc
(0x55, __svgalib_inCR
(0x55) & ~
1);
__svgalib_outcrtc
(0x01, CR1
); /* Unblank screen. */
}
#ifdef S3_LINEAR_SUPPORT
if (mode
== TEXT
&& s3_linear_addr
)
s3_linear_disable
(); /* make sure linear is off */
#endif
/* restore CR38/39 (may lock other regs) */
if (mode
== TEXT
) {
/* restore lock registers as well */
__svgalib_outCR
(0x40, regs
[S3_CR40
]);
__svgalib_outCR
(0x39, regs
[S3_CR39
]);
__svgalib_outCR
(0x38, regs
[S3_CR38
]);
} else
s3_lock_enh
();
}
/*
* Initialize register state for a mode.
*/
static void s3_initializemode
(unsigned char *moderegs
,
ModeTiming
* modetiming
, ModeInfo
* modeinfo
)
{
/* Get current values. */
s3_saveregs
(moderegs
);
/* Set up the standard VGA registers for a generic SVGA. */
__svgalib_setup_VGA_registers
(moderegs
, modetiming
, modeinfo
);
/* Set up the extended register values, including modifications */
/* of standard VGA registers. */
moderegs
[VGA_SR0
] = 0x03;
moderegs
[VGA_CR13
] = modeinfo
->lineWidth
>> 3;
moderegs
[VGA_CR17
] = 0xE3;
if (modeinfo
->lineWidth
/ modeinfo
->bytesPerPixel
== 2048)
moderegs
[S3_CR31
] = 0x8F;
else
moderegs
[S3_CR31
] = 0x8D;
#ifdef S3_LINEAR_MODE_BANKING_864
if (s3_chiptype
>= S3_864
) {
/* moderegs[S3_ENHANCEDMODE] |= 0x01; */
/* Enable enhanced memory mode. */
moderegs
[S3_CR31
] |= 0x04;
/* Enable banking via CR6A in linear mode. */
moderegs
[S3_CR31
] |= 0x01;
}
#endif
moderegs
[S3_CR32
] = 0;
moderegs
[S3_CR33
] = 0x20;
moderegs
[S3_CR34
] = 0x10; /* 1024 */
moderegs
[S3_CR35
] = 0;
/* Call cebank() here when setting registers. */
if (modeinfo
->bitsPerPixel
>= 8) {
moderegs
[S3_CR3A
] = 0xB5;
if (s3_chiptype
== S3_928
)
/* ARI: Turn on CHAIN4 for 928, since __svgalib_setup_VGA_registers
initializes ModeX */
moderegs
[VGA_CR14
] = 0x60;
} else {
/* 16 color mode */
moderegs
[VGA_CR13
] = modeinfo
->lineWidth
>> 1;
moderegs
[VGA_GR0
] = 0x0F;
moderegs
[VGA_GR1
] = 0x0F;
moderegs
[VGA_GR5
] = 0x00; /* write mode 0 */
moderegs
[VGA_AR11
] = 0x00;
moderegs
[S3_CR3A
] = 0x85;
}
moderegs
[S3_CR3B
] = (moderegs
[VGA_CR0
] + moderegs
[VGA_CR4
] + 1) / 2;
moderegs
[S3_CR3C
] = moderegs
[VGA_CR0
] / 2;
if (s3_chiptype
== S3_911
) {
moderegs
[S3_CR40
] &= 0xF2;
moderegs
[S3_CR40
] |= 0x09;
} else if (s3_flags
& S3_LOCALBUS
) {
moderegs
[S3_CR40
] &= 0xF2;
/* Pegasus wants 0x01 for zero wait states. */
#ifdef S3_0_WAIT_805_864
moderegs
[S3_CR40
] |= 0x09; /* use fifo + 0 wait state */
#else
moderegs
[S3_CR40
] |= 0x05;
#endif
} else {
moderegs
[S3_CR40
] &= 0xF6;
moderegs
[S3_CR40
] |= 0x01;
}
if (modeinfo
->bitsPerPixel
>= 24) {
/* 24/32 bit color */
if (s3_chiptype
== S3_864
|| s3_chiptype
== S3_964
)
moderegs
[S3_CR43
] = 0x08;
else if (s3_chiptype
== S3_928
&& dac_used
->id
== SIERRA_15025
)
moderegs
[S3_CR43
] = 0x01; /* ELSA Winner 1000 */
} else if (modeinfo
->bitsPerPixel
>= 15) {
/* 15/16 bit color */
if (s3_chiptype
<= S3_864
|| s3_chiptype
>= S3_866
) { /* XXXX Trio? */
moderegs
[S3_CR43
] = 0x08;
if (dac_used
->id
== IBMRGB52x
)
moderegs
[S3_CR43
] = 0x10;
else if (s3_chiptype
== S3_928
&& dac_used
->id
== SIERRA_15025
)
moderegs
[S3_CR43
] = 0x01;
if (s3_chiptype
<= S3_924
&& dac_used
->id
!= NORMAL_DAC
)
moderegs
[S3_CR43
] = 0x01;
} else
/* XXXX some DAC might need this; XF86 source says... */
moderegs
[S3_CR43
] = 0x09;
} else {
/* 4/8 bit color */
moderegs
[S3_CR43
] = 0x00;
}
if (s3_chiptype
>= S3_924
&& s3_chiptype
<= S3_928
) { /* different for 864+ */
s3_8514regs
[S3_ADVFUNC_CNTL
] = 0x0002;
if ((s3_chiptype
== S3_928
&& modeinfo
->bitsPerPixel
!= 4) || !(s3_flags
& S3_OLD_STEPPING
))
s3_8514regs
[S3_ADVFUNC_CNTL
] |= 0x0001;
if (modeinfo
->bitsPerPixel
== 4)
s3_8514regs
[S3_ADVFUNC_CNTL
] |= 0x0004;
#if 0
/* 864 databook says it is for enhanced 4bpp */
if (modeinfo
->lineWidth
> 640)
s3_8514regs
[S3_ADVFUNC_CNTL
] |= 0x0004;
#endif
} else if (s3_chiptype
== S3_968
) {
s3_8514regs
[S3_ADVFUNC_CNTL
] = 0x0002;
if (modeinfo
->bitsPerPixel
== 4)
s3_8514regs
[S3_ADVFUNC_CNTL
] |= 0x0004;
#ifdef PIXEL_MULTIPLEXING
else
s3_8514regs
[S3_ADVFUNC_CNTL
] |= 0x0001;
#endif
} else if (modeinfo
->lineWidth
/ modeinfo
->bytesPerPixel
== 1024)
s3_8514regs
[S3_ADVFUNC_CNTL
] = 0x0007;
else
s3_8514regs
[S3_ADVFUNC_CNTL
] = 0x0003;
moderegs
[S3_CR44
] = 0;
/* Skip CR45, 'hi/truecolor cursor color enable'. */
if (s3_chiptype
>= S3_801
) {
int m
, n
; /* for FIFO balancing */
/* XXXX Not all chips support all widths. */
moderegs
[S3_CR50
] &= ~
0xF1;
switch (modeinfo
->bitsPerPixel
) {
case 16:
moderegs
[S3_CR50
] |= 0x10;
break;
case 24: /* XXXX 868/968 only */
if (s3_chiptype
>= S3_868
)
moderegs
[S3_CR50
] |= 0x20;
break;
case 32:
moderegs
[S3_CR50
] |= 0x30;
break;
}
switch (modeinfo
->lineWidth
/ modeinfo
->bytesPerPixel
) {
case 640:
moderegs
[S3_CR50
] |= 0x40;
break;
case 800:
moderegs
[S3_CR50
] |= 0x80;
break;
case 1152:
if (!(s3_flags
& S3_OLD_STEPPING
)) {
moderegs
[S3_CR50
] |= 0x01;
break;
} /* else fall through */
case 1280:
moderegs
[S3_CR50
] |= 0xC0;
break;
case 1600:
moderegs
[S3_CR50
] |= 0x81;
break;
/* 1024/2048 no change. */
}
moderegs
[S3_CR51
] &= 0xC0;
moderegs
[S3_CR51
] |= (modeinfo
->lineWidth
>> 7) & 0x30;
/* moderegs[S3_CR53] |= 0x10; *//* Enable MMIO. */
/* moderegs[S3_CR53] |= 0x20; *//* DRAM interleaving for S3_805i with 2MB */
n
= 0xFF;
if (s3_chiptype
>= S3_864
||
s3_chiptype
== S3_801
|| s3_chiptype
== S3_805
) {
/*
* CRT FIFO balancing for DRAM cards and 964/968
* in VGA mode.
*/
int clock, mclk
;
if (modeinfo
->bitsPerPixel
< 8) {
clock = modetiming
->pixelClock
;
} else {
clock = modetiming
->pixelClock
*
modeinfo
->bytesPerPixel
;
}
if (s3_memory
< 2048 || s3_chiptype
== S3_TRIO32
)
clock *= 2;
if (__svgalib_s3_s3Mclk
> 0)
mclk
= __svgalib_s3_s3Mclk
;
else if (s3_chiptype
== S3_801
|| s3_chiptype
== S3_805
)
mclk
= 50000; /* Assumption. */
else
mclk
= 60000; /* Assumption. */
m
= (int) ((mclk
/ 1000.0 * .72 + 16.867) * 89.736 / (clock / 1000.0 + 39) - 21.1543);
if (s3_memory
< 2048 || s3_chiptype
== S3_TRIO32
)
m
/= 2;
if (m
> 31)
m
= 31;
else if (m
< 0) {
m
= 0;
n
= 16;
}
} else if (s3_memory
== 512 || modetiming
->HDisplay
> 1200)
m
= 0;
else if (s3_memory
== 1024)
m
= 2;
else
m
= 20;
moderegs
[S3_CR54
] = m
<< 3;
moderegs
[S3_CR60
] = n
;
moderegs
[S3_CR55
] &= 0x08;
moderegs
[S3_CR55
] |= 0x40;
#ifdef S3_LINEAR_MODE_BANKING_864
if (s3_chiptype
>= S3_864
) {
if (modeinfo
->bitsPerPixel
>= 8) {
/* Enable linear addressing. */
moderegs
[S3_CR58
] |= 0x10;
/* Set window size to 64K. */
moderegs
[S3_CR58
] &= ~
0x03;
/* Assume CR59/5A are correctly set up for 0xA0000. */
/* Set CR6A linear bank to zero. */
moderegs
[S3_CR6A
] &= ~
0x3F;
/* use alternate __svgalib_setpage() function */
__svgalib_s3_driverspecs.__svgalib_setpage
= s3_setpage864
;
} else {
/* doesn't work for 4bpp. */
__svgalib_s3_driverspecs.__svgalib_setpage
= s3_setpage
;
}
}
#endif
#ifdef S3_LINEAR_SUPPORT
moderegs
[S3_CR59
] = s3_cr59
;
moderegs
[S3_CR5A
] = s3_cr5A
;
#endif
/* Extended CRTC timing. */
moderegs
[S3_CR5E
] =
(((modetiming
->CrtcVTotal
- 2) & 0x400) >> 10) |
(((modetiming
->CrtcVDisplay
- 1) & 0x400) >> 9) |
(((modetiming
->CrtcVSyncStart
) & 0x400) >> 8) |
(((modetiming
->CrtcVSyncStart
) & 0x400) >> 6) | 0x40;
{
int i
, j
;
i
= ((((modetiming
->CrtcHTotal
>> 3) - 5) & 0x100) >> 8) |
((((modetiming
->CrtcHDisplay
>> 3) - 1) & 0x100) >> 7) |
((((modetiming
->CrtcHSyncStart
>> 3) - 1) & 0x100) >> 6) |
((modetiming
->CrtcHSyncStart
& 0x800) >> 7);
if ((modetiming
->CrtcHSyncEnd
>> 3) - (modetiming
->CrtcHSyncStart
>> 3) > 64)
i
|= 0x08;
if ((modetiming
->CrtcHSyncEnd
>> 3) - (modetiming
->CrtcHSyncStart
>> 3) > 32)
i
|= 0x20;
j
= ((moderegs
[VGA_CR0
] + ((i
& 0x01) << 8) +
moderegs
[VGA_CR4
] + ((i
& 0x10) << 4) + 1) / 2);
if (j
- (moderegs
[VGA_CR4
] + ((i
& 0x10) << 4)) < 4) {
if (moderegs
[VGA_CR4
] + ((i
& 0x10) << 4) + 4 <= moderegs
[VGA_CR0
] + ((i
& 0x01) << 8))
j
= moderegs
[VGA_CR4
] + ((i
& 0x10) << 4) + 4;
else
j
= moderegs
[VGA_CR0
] + ((i
& 0x01) << 8) + 1;
}
moderegs
[S3_CR3B
] = j
& 0xFF;
i
|= (j
& 0x100) >> 2;
/* Interlace mode frame offset. */
moderegs
[S3_CR3C
] = (moderegs
[VGA_CR0
] + ((i
& 0x01) << 8)) / 2;
moderegs
[S3_CR5D
] = (moderegs
[S3_CR5D
] & 0x80) | i
;
}
{
int i
;
if (modeinfo
->bitsPerPixel
< 8)
i
= modetiming
->HDisplay
/ 4 + 1;
else
i
= modetiming
->HDisplay
*
modeinfo
->bytesPerPixel
/ 4 + 1;
moderegs
[S3_CR61
] = (i
>> 8) | 0x80;
moderegs
[S3_CR62
] = i
& 0xFF;
}
} /* 801+ */
if (modetiming
->flags
& INTERLACED
)
moderegs
[S3_CR42
] |= 0x20;
/*
* Clock select works as follows:
* Clocks 0 and 1 (VGA 25 and 28 MHz) can be selected via the
* two VGA MiscOutput clock select bits.
* If 0x3 is written to these bits, the selected clock index
* is taken from the S3 clock select register at CR42. Clock
* indices 0 and 1 should correspond to the VGA ones above,
* and 3 is often 0 MHz, followed by extended clocks for a
* total of mostly 16.
*/
if (modetiming
->flags
& USEPROGRCLOCK
)
moderegs
[VGA_MISCOUTPUT
] |= 0x0C; /* External clock select. */
else if (modetiming
->selectedClockNo
< 2) {
/* Program clock select bits 0 and 1. */
moderegs
[VGA_MISCOUTPUT
] &= ~
0x0C;
moderegs
[VGA_MISCOUTPUT
] |=
(modetiming
->selectedClockNo
& 3) << 2;
} else if (modetiming
->selectedClockNo
>= 2) {
moderegs
[VGA_MISCOUTPUT
] |= 0x0C;
/* Program S3 clock select bits. */
moderegs
[S3_CR42
] &= ~
0x1F;
moderegs
[S3_CR42
] |=
modetiming
->selectedClockNo
;
}
if (s3_chiptype
== S3_TRIO64
|| s3_chiptype
== S3_765
) {
moderegs
[S3_CR33
] &= ~
0x08;
if (modeinfo
->bitsPerPixel
== 16)
moderegs
[S3_CR33
] |= 0x08;
/*
* The rest of the DAC/clocking is setup by the
* Trio64 code in the RAMDAC interface (ramdac.c).
*/
}
if (dac_used
->id
!= NORMAL_DAC
) {
int colormode
;
colormode
= __svgalib_colorbits_to_colormode
(modeinfo
->bitsPerPixel
,
modeinfo
->colorBits
);
dac_used
->initializeState
(&moderegs
[S3_DAC_OFFSET
],
modeinfo
->bitsPerPixel
, colormode
,
modetiming
->pixelClock
);
if (dac_used
->id
== ATT20C490
) {
int pixmux
, invert_vclk
, blank_delay
;
pixmux
= 0;
invert_vclk
= 0;
blank_delay
= 2;
if (colormode
== CLUT8_6
&& modetiming
->pixelClock
>= 67500) {
pixmux
= 0x00;
invert_vclk
= 1;
} else if (colormode
== CLUT8_8
)
pixmux
= 0x02;
else if (colormode
== RGB16_555
)
pixmux
= 0xa0;
else if (colormode
== RGB16_565
)
pixmux
= 0xc0;
else if (colormode
== RGB24_888_B
)
pixmux
= 0xe0;
moderegs
[S3_CR67
] = pixmux
| invert_vclk
;
moderegs
[S3_CR6D
] = blank_delay
;
}
if (dac_used
->id
== S3_SDAC
) {
int pixmux
, invert_vclk
, blank_delay
;
pixmux
= 0;
invert_vclk
= 0;
blank_delay
= 0;
if (colormode
== CLUT8_6
&& modetiming
->pixelClock
>= 67500) {
#ifdef SDAC_8BPP_PIXMUX
/* x64 8bpp pixel multiplexing? */
pixmux
= 0x10;
if (s3_chiptype
!= S3_866
&& s3_chiptype
!= S3_868
)
invert_vclk
= 1;
blank_delay
= 2;
#endif
} else if (colormode
== RGB16_555
) {
pixmux
= 0x30;
blank_delay
= 2;
} else if (colormode
== RGB16_565
) {
pixmux
= 0x50;
blank_delay
= 2;
} else if (colormode
== RGB24_888_B
) { /* XXXX 868/968 only */
pixmux
= 0x90;
blank_delay
= 2;
} else if (colormode
== RGB32_888_B
) {
pixmux
= 0x70;
blank_delay
= 2;
}
moderegs
[S3_CR67
] = pixmux
| invert_vclk
;
moderegs
[S3_CR6D
] = blank_delay
;
/* Clock select. */
moderegs
[S3_CR42
] &= ~
0x0F;
moderegs
[S3_CR42
] |= 0x02;
}
if (dac_used
->id
== IBMRGB52x
) {
unsigned char pixmux
, blank_delay
, tmp
;
tmp
= 0;
pixmux
= 0x11;
blank_delay
= 0;
if (modeinfo
->bitsPerPixel
< 8 || colormode
== RGB32_888_B
)
pixmux
= 0x00;
moderegs
[S3_CR58
] |= 0x40;
moderegs
[S3_CR65
] = 0;
moderegs
[S3_CR66
] &= 0xf8;
moderegs
[S3_CR66
] |= tmp
;
#ifdef PIXEL_MULTIPLEXING
moderegs
[S3_CR67
] = pixmux
;
#endif
moderegs
[S3_CR6D
] = blank_delay
;
/* Clock select. */
moderegs
[S3_CR42
] &= ~
0x0F;
moderegs
[S3_CR42
] |= 0x02;
}
}
#ifdef S3_LINEAR_SUPPORT
s3_cr58
= moderegs
[S3_CR58
];
s3_cr40
= moderegs
[S3_CR40
];
s3_cr54
= moderegs
[S3_CR54
];
#endif
if (clk_used
== &__svgalib_I2061A_clockchip_methods
&&
(modetiming
->flags
& USEPROGRCLOCK
)) {
/* Clock select. */
moderegs
[S3_CR42
] &= ~
0x0F;
moderegs
[S3_CR42
] |= 0x02;
}
/* update the 8514 regs */
memcpy(moderegs
+ S3_8514_OFFSET
, s3_8514regs
, S3_8514_COUNT
* 2);
}
/* Set a mode */
static int s3_setmode
(int mode
, int prv_mode
)
{
ModeInfo
*modeinfo
;
ModeTiming
*modetiming
;
unsigned char moderegs
[S3_TOTAL_REGS
];
int res
;
if (IS_IN_STANDARD_VGA_DRIVER
(mode
)) {
/* Let the standard VGA driver set standard VGA modes. */
res
= __svgalib_vga_driverspecs.
setmode(mode
, prv_mode
);
if (res
== 0) {
/*
* ARI: Turn off virtual size of 1024 - this fixes all problems
* with standard modes, including 320x200x256.
*
* SL: Is this for 928 only? Doesn't matter for 805.
*
* MZ: Affects 765 as well, so I assume it is good for all chipsets.
*/
s3_unlock
();
__svgalib_outCR
(0x34, __svgalib_inCR
(0x34) & ~
0x10);
s3_lock
();
}
return res
;
}
if (!s3_modeavailable
(mode
))
return 1;
modeinfo
= __svgalib_createModeInfoStructureForSvgalibMode
(mode
);
modetiming
= malloc(sizeof(ModeTiming
));
if (__svgalib_getmodetiming
(modetiming
, modeinfo
, cardspecs
)) {
free(modetiming
);
free(modeinfo
);
return 1;
}
/* Adjust the display width. */
modeinfo
->lineWidth
= s3_adjlinewidth
(modeinfo
->lineWidth
);
CI.
xbytes = modeinfo
->lineWidth
;
s3_initializemode
(moderegs
, modetiming
, modeinfo
);
free(modeinfo
);
free(modetiming
);
__svgalib_setregs
(moderegs
); /* Set standard regs. */
s3_setregs
(moderegs
, mode
); /* Set extended regs. */
return 0;
}
/* Indentify chipset; return non-zero if detected */
/* Some port I/O functions: */
static unsigned char rdinx
(int port
, unsigned char index
)
{
outb
(port
, index
);
return port_in
(port
+ 1);
}
static void wrinx
(int port
, unsigned char index
, unsigned char val
)
{
outb
(port
, index
);
outb
(port
+ 1, val
);
}
/*
* Returns true iff the bits in 'mask' of register 'port', index 'index'
* are read/write.
*/
static int testinx2
(int port
, unsigned char index
, unsigned char mask
)
{
unsigned char old
, new1
, new2
;
old
= rdinx
(port
, index
);
wrinx
(port
, index
, (old
& ~mask
));
new1
= rdinx
(port
, index
) & mask
;
wrinx
(port
, index
, (old
| mask
));
new2
= rdinx
(port
, index
) & mask
;
wrinx
(port
, index
, old
);
return (new1
== 0) && (new2
== mask
);
}
int s3_test
(void)
{
int vgaIOBase
, vgaCRIndex
, vgaCRReg
;
vgaIOBase
= (port_in
(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
vgaCRIndex
= vgaIOBase
+ 4;
vgaCRReg
= vgaIOBase
+ 5;
outb
(vgaCRIndex
, 0x11); /* for register CR11, (Vertical Retrace End) */
outb
(vgaCRReg
, 0x00); /* set to 0 */
outb
(vgaCRIndex
, 0x38); /* check if we have an S3 */
outb
(vgaCRReg
, 0x00);
/* Make sure we can't write when locked */
if (testinx2
(vgaCRIndex
, 0x35, 0x0f))
return 0;
outb
(vgaCRIndex
, 0x38); /* for register CR38, (REG_LOCK1) */
outb
(vgaCRReg
, 0x48); /* unlock S3 register set for read/write */
/* Make sure we can write when unlocked */
if (!testinx2
(vgaCRIndex
, 0x35, 0x0f))
return 0;
if (s3_init
(0, 0, 0)) /* type not OK */
return 0;
return 1;
}
/*
* Bank switching function - set 64K bank number
*
* XXXX locking and unlocking might hurt performance but is safer.
*/
static void s3_setpage
(int page
)
{
#ifdef S3_16_COLORS
/*
* XXXX adjust the parameter for 4bpp (1bpp is ignored). Shouldn't
* need this, but either me or the drawing functions are making bad
* assumptions about 4bpp.
*/
if (infotable
[CM
].
bytesperpixel == 0)
page
*= 4;
#endif
#ifdef S3_KLUDGE_PAGE_MODE
/* adjust to use 256K pages */
if (CM
== G320x200x256
)
page
*= 4;
#endif
s3_unlock
();
outb
(CRT_IC
, 0x35);
outb
(CRT_DC
, (port_in
(CRT_DC
) & 0xF0) | (page
& 0x0F));
if (s3_chiptype
>= S3_801
) {
outb
(CRT_IC
, 0x51);
outb
(CRT_DC
, (port_in
(CRT_DC
) & ~
0x0C) | ((page
& 0x30) >> 2));
}
port_in
(CRT_DC
); /* ARI: Ferraro says: required for first generation 911 only */
s3_lock
();
}
/*
* Bank switching function - set 64K bank number for 864+
* (not for 4bpp)
*
* XXXX locking and unlocking might hurt performance
* (864 shouldn't need it).
*/
#ifdef S3_LINEAR_MODE_BANKING_864
static void s3_setpage864
(int page
)
{
s3_unlock
();
/* "Linear" mode banking. */
outb
(CRT_IC
, 0x6A);
outb
(CRT_DC
, (port_in
(CRT_DC
) & ~
0x3F) | page
);
s3_lock
();
}
#endif
/*
* Set display start address (not for 16 color modes).
*
* This works up to 4Mb (should be able to go higher).
*
* XXXX locking and unlocking might hurt performance but is safer.
*/
static void s3_setdisplaystart
(int address
)
{
#ifdef S3_KLUDGE_PAGE_MODE
/* adjust to use 256K pages */
if (CM
== G320x200x256
)
address
*= 4;
#endif
s3_unlock
();
outw
(CRT_IC
, 0x0d | ((address
<< 6) & 0xff00)); /* sa2-sa9 */
outw
(CRT_IC
, 0x0c | ((address
>> 2) & 0xff00)); /* sa10-sa17 */
port_in
(0x3da); /* set ATC to addressing mode */
outb
(ATT_IW
, 0x13 + 0x20); /* select ATC reg 0x13 */
outb
(ATT_IW
, (port_in
(ATT_R
) & 0xf0) | ((address
& 3) << 1));
/* write sa0-1 to bits 1-2 */
outb
(CRT_IC
, 0x31);
outb
(CRT_DC
, (port_in
(CRT_DC
) & ~
0x30) | ((address
& 0xc0000) >> 14));
if (s3_chiptype
>= S3_801
) {
outb
(CRT_IC
, 0x51);
outb
(CRT_DC
, (port_in
(CRT_DC
) & ~
0x03) | ((address
& 0x300000) >> 20));
}
s3_lock
();
}
/*
* Set logical scanline length (Multiples of 8 to 8184).
* CR43.2 should be 0 for this.
*/
static void s3_setlogicalwidth
(int width
)
{
__svgalib_outCR
(0x13, (width
>> 3)); /* lw3-lw11 */
__svgalib_outCR
(0x51, (width
& 0x300) >> 4); /* lw12-lw13 */
}
#ifdef S3_LINEAR_SUPPORT
static void s3_linear_enable
(void)
{
s3_unlock
();
if (s3_chiptype
> S3_924
) {
int i
;
outb
(CRT_IC
, 0x40);
i
= (s3_cr40
& 0xf6) | 0x0a;
outb
(CRT_DC
, (unsigned char) i
);
outb
(CRT_IC
, 0x58);
outb
(CRT_DC
, s3_linear_opt
| s3_cr58
);
if (s3_chiptype
> S3_928
) {
outb
(CRT_IC
, 0x54);
outb
(CRT_DC
, (s3_cr54
+ 0x07));
}
}
s3_lock
();
}
static void s3_linear_disable
(void)
{
s3_unlock
();
if (s3_chiptype
> S3_924
) {
if (s3_chiptype
> S3_928
) {
outb
(CRT_IC
, 0x54);
outb
(CRT_DC
, s3_cr54
);
}
outb
(CRT_IC
, 0x58);
outb
(CRT_DC
, s3_cr58
);
outb
(CRT_IC
, 0x40);
outb
(CRT_DC
, s3_cr40
);
}
s3_lock
();
}
/* Set linear addressing mode */
static int s3_linear
(int op
, int param
)
{
if (op
== LINEAR_QUERY_BASE
)
return s3_linear_base
;
if (op
== LINEAR_QUERY_GRANULARITY
) {
switch (s3_memory
) {
case 4096:
case 2048:
case 1024:
return s3_memory
* 1024;
default:
return 1024 * 1024;
}
} else if (op
== LINEAR_QUERY_RANGE
)
return 256;
else if (op
== LINEAR_ENABLE
) {
s3_setpage
(0);
s3_linear_enable
();
s3_linear_addr
= param
;
return 0;
} else if (op
== LINEAR_DISABLE
) {
s3_setpage
(0);
s3_linear_disable
();
s3_linear_addr
= 0;
return 0;
} else
return -1;
}
#define S3_LINEAR_FUNC s3_linear
#else
#define S3_LINEAR_FUNC 0
#endif /* S3_LINEAR_SUPPORT */
/* Function table (exported) */
DriverSpecs __svgalib_s3_driverspecs
=
{
s3_saveregs
, /* saveregs */
s3_setregs
, /* setregs */
(void (*)(void)) nothing
, /* unlock */
(void (*)(void)) nothing
, /* lock */
s3_test
,
s3_init
,
s3_setpage
,
(void (*)(int)) nothing
,
(void (*)(int)) nothing
,
s3_setmode
,
s3_modeavailable
,
s3_setdisplaystart
,
s3_setlogicalwidth
,
s3_getmodeinfo
,
0, /* bitblt */
0, /* imageblt */
0, /* fillblt */
0, /* hlinelistblt */
0, /* bltwait */
s3_ext_set
, /* extset */
0, /* accel */
S3_LINEAR_FUNC
, /* linear */
NULL
, /* Accelspecs */
NULL
, /* Emulation */
};
/* Initialize driver (called after detection) */
/* Derived from XFree86 SuperProbe and s3 driver. */
static DacMethods
*dacs_to_probe
[] =
{
#ifdef INCLUDE_S3_SDAC_DAC_TEST
&__svgalib_S3_SDAC_methods
,
#endif
#ifdef INCLUDE_S3_GENDAC_DAC_TEST
&__svgalib_S3_GENDAC_methods
,
#endif
#ifdef INCLUDE_ATT20C490_DAC_TEST
&__svgalib_ATT20C490_methods
,
#endif
#ifdef INCLUDE_SC15025_DAC_TEST
&__svgalib_SC15025_methods
,
#endif
#ifdef INCLUDE_SC1148X_DAC_TEST
&__svgalib_SC1148X_methods
,
#endif
#ifdef INCLUDE_IBMRGB52x_DAC_TEST
&__svgalib_IBMRGB52x_methods
,
#endif
NULL
};
static int s3_init
(int force
, int par1
, int par2
)
{
int id
, rev
, config
;
s3_unlock
();
s3_flags
= 0; /* initialize */
id
= __svgalib_inCR
(0x30); /* Get chip id. */
rev
= id
& 0x0F;
if (id
>= 0xE0) {
id
|= __svgalib_inCR
(0x2E) << 8;
rev
|= __svgalib_inCR
(0x2F) << 4;
}
if (force
) {
s3_chiptype
= par1
; /* we already know the type */
s3_memory
= par2
;
/* ARI: can we really trust the user's specification, or should we ignore
it and probe ourselves ? */
if (s3_chiptype
== S3_801
|| s3_chiptype
== S3_805
) {
if ((rev
& 0x0F) < 2)
s3_flags
|= S3_OLD_STEPPING
; /* can't handle 1152 width */
} else if (s3_chiptype
== S3_928
) {
if ((rev
& 0x0F) < 4) /* ARI: Stepping D or below */
s3_flags
|= S3_OLD_STEPPING
; /* can't handle 1152 width */
}
} else {
s3_chiptype
= -1;
config
= __svgalib_inCR
(0x36); /* get configuration info */
switch (id
& 0xf0) {
case 0x80:
if (rev
== 1) {
s3_chiptype
= S3_911
;
break;
}
if (rev
== 2) {
s3_chiptype
= S3_924
;
break;
}
break;
case 0xa0:
switch (config
& 0x03) {
case 0x00:
case 0x01:
/* EISA or VLB - 805 */
s3_chiptype
= S3_805
;
/* ARI: Test stepping: 0:B, 1:unknown, 2,3,4:C, 8:I, >=5:D */
if ((rev
& 0x0F) < 2)
s3_flags
|= S3_OLD_STEPPING
; /* can't handle 1152 width */
break;
case 0x03:
/* ISA - 801 */
s3_chiptype
= S3_801
;
/* Stepping same as 805, just ISA */
if ((rev
& 0x0F) < 2)
s3_flags
|= S3_OLD_STEPPING
; /* can't handle 1152 width */
break;
}
break;
case 0x90:
s3_chiptype
= S3_928
;
if ((rev
& 0x0F) < 4) /* ARI: Stepping D or below */
s3_flags
|= S3_OLD_STEPPING
; /* can't handle 1152 width */
break;
case 0xB0:
/* 928P */
s3_chiptype
= S3_928
;
break;
case 0xC0:
s3_chiptype
= S3_864
;
break;
case 0xD0:
s3_chiptype
= S3_964
;
break;
case 0xE0:
switch (id
& 0xFFF0) {
case 0x10E0:
s3_chiptype
= S3_TRIO32
;
break;
case 0x3DE0: /* ViRGE/VX ID */
case 0x31E0: /* ViRGE ID */
case 0x01E0: /* S3Trio64V2/DX ... any others? */
case 0x04E0:
case 0x11E0:
if (rev
& 0x0400)
s3_chiptype
= S3_765
;
else
s3_chiptype
= S3_TRIO64
;
break;
case 0x80E0:
s3_chiptype
= S3_866
;
break;
case 0x90E0:
s3_chiptype
= S3_868
;
break;
case 0xF0E0: /* XXXX From data book; XF86 says 0xB0E0? */
s3_chiptype
= S3_968
;
break;
}
}
if (s3_chiptype
== -1) {
printk
(KERN_ERR
"svgalib: S3: Unknown chip id %02x\n",
id
);
return -1;
}
if (s3_chiptype
<= S3_924
) {
if ((config
& 0x20) != 0)
s3_memory
= 512;
else
s3_memory
= 1024;
} else {
/* look at bits 5, 6 and 7 */
switch ((config
& 0xE0) >> 5) {
case 0:
s3_memory
= 4096;
break;
case 2:
s3_memory
= 3072;
break;
case 3:
s3_memory
= 8192;
break;
case 4:
s3_memory
= 2048;
break;
case 5:
s3_memory
= 6144;
break;
case 6:
s3_memory
= 1024;
break;
case 7:
s3_memory
= 512;
break; /* Trio32 */
}
}
if ((config
& 0x03) < 3) /* XXXX 928P is ignored */
s3_flags
|= S3_LOCALBUS
;
}
if (__svgalib_driver_report
) {
printk
(KERN_INFO
"svgalib: Using S3 driver (%s, %dK).\n", s3_chipname
[s3_chiptype
],
s3_memory
);
if (s3_flags
& S3_OLD_STEPPING
)
printk
(KERN_INFO
"svgalib: Chip revision cannot handle modes with width 1152.\n");
if (s3_chiptype
> S3_TRIO64
) {
printk
(KERN_INFO
"svgalib: s3: chipsets newer than S3 Trio64 is not supported well yet.\n");
}
}
/* begin: Initialize cardspecs. */
#ifdef S3_LINEAR_SUPPORT
if (s3_chiptype
> S3_805
) {
int found_pciconfig
;
unsigned long pci_conf
[64];
found_pciconfig
= __svgalib_pci_find_vendor_vga
(0x5333, pci_conf
, 0);
if (!found_pciconfig
)
s3_linear_base
= pci_conf
[4] & 0xFF800000;
}
s3_cr59
= s3_linear_base
>> 24;
s3_cr5A
= (s3_linear_base
>> 16);
if (! (s3_cr59
| s3_cr5A
)) {
s3_cr59
= __svgalib_inCR
(0x59);
s3_cr5A
= __svgalib_inCR
(0x5A);
if (!s3_cr59
) {
s3_cr59
= 0xF3000000 >> 24;
s3_cr5A
= (0xF3000000 >> 16);
}
s3_linear_base
= (s3_cr59
<< 24) | (s3_cr5A
<< 16);
}
s3_linear_opt
|= 0x10;
switch (s3_memory
) {
case 512 :
case 1024 :
s3_linear_opt
|= 0x01;
break;
case 2048 :
s3_linear_opt
|= 0x02;
break;
case 3072 :
case 4096 :
case 6144 :
case 8192 :
s3_linear_opt
|= 0x03;
break;
default :
s3_linear_opt
= 0x14; /* like XFree */
}
#endif
cardspecs
= malloc(sizeof(CardSpecs
));
cardspecs
->videoMemory
= s3_memory
;
cardspecs
->nClocks
= 0;
/* cardspecs->maxHorizontalCrtc = 2040; SL: kills 800x600x32k and above */
cardspecs
->maxHorizontalCrtc
= 4088;
cardspecs
->flags
= INTERLACE_DIVIDE_VERT
;
dac_used
= NULL
;
clk_used
= NULL
;
#ifdef INCLUDE_S3_TRIO64_DAC
if ((s3_chiptype
== S3_TRIO64
|| s3_chiptype
== S3_765
) && dac_used
== NULL
)
dac_used
= &__svgalib_Trio64_methods
;
#endif
if (dac_used
== NULL
) {
/* Not supported. */
printk
(KERN_ERR
"svgalib: s3: Assuming S3_SDAC.\n");
dac_used
= &__svgalib_S3_SDAC_methods
;
dac_used
->initialize
();
}
if (clk_used
)
clk_used
->initialize
(cardspecs
, dac_used
);
dac_used
->qualifyCardSpecs
(cardspecs
, dac_speed
);
/* Initialize standard clocks for unknown DAC. */
if ((!(cardspecs
->flags
& CLOCK_PROGRAMMABLE
))
&& cardspecs
->nClocks
== 0) {
/*
* Almost all cards have 25 and 28 MHz on VGA clocks 0 and 1,
* so use these for an unknown DAC, yielding 640x480x256.
*/
cardspecs
->nClocks
= 2;
cardspecs
->clocks
= malloc(sizeof(int) * 2);
cardspecs
->clocks
[0] = 25175;
cardspecs
->clocks
[1] = 28322;
}
/* Limit pixel clocks according to chip specifications. */
if (s3_chiptype
== S3_864
|| s3_chiptype
== S3_868
) {
/* Limit max clocks according to 95 MHz DCLK spec. */
/* SL: might just be 95000 for 4/8bpp since no pixmux'ing */
LIMIT
(cardspecs
->maxPixelClock4bpp
, 95000 * 2);
LIMIT
(cardspecs
->maxPixelClock8bpp
, 95000 * 2);
LIMIT
(cardspecs
->maxPixelClock16bpp
, 95000);
/* see explanation below */
LIMIT
(cardspecs
->maxPixelClock24bpp
, 36000);
/*
* The official 32bpp limit is 47500, but we allow
* 50 MHz for VESA 800x600 timing (actually the
* S3-864 doesn't have the horizontal timing range
* to run unmodified VESA 800x600 72 Hz timings).
*/
LIMIT
(cardspecs
->maxPixelClock32bpp
, 50000);
}
#ifndef S3_16_COLORS
cardspecs
->maxPixelClock4bpp
= 0; /* 16-color doesn't work. */
#endif
/* end: Initialize cardspecs. */
__svgalib_driverspecs
= &__svgalib_s3_driverspecs
;
__svgalib_banked_mem_base
=0xa0000;
__svgalib_banked_mem_size
=0x10000;
#ifdef S3_LINEAR_SUPPORT
__svgalib_linear_mem_base
=s3_linear_base
;
__svgalib_linear_mem_size
=s3_memory
*0x400;
#endif
sleep
(4);
return 0;
}