#include "accel.h"
#include "savage.h"
static bool
Savage_GetColorSpaceParams(int colorSpace, uint32& bitsPerPixel, uint32& maxPixelClock)
{
switch (colorSpace) {
case B_RGB32:
bitsPerPixel = 32;
maxPixelClock = 220000;
break;
case B_RGB16:
bitsPerPixel = 16;
maxPixelClock = 250000;
break;
case B_CMAP8:
bitsPerPixel = 8;
maxPixelClock = 250000;
break;
default:
TRACE("Unsupported color space: 0x%X\n", colorSpace);
return false;
}
return true;
}
static void
WaitQueue3D(uint32 v)
{
uint32 slots = MAXFIFO - v;
while ((STATUS_WORD0 & 0x0000ffff) > slots);
}
static void
WaitQueue4(uint32 v)
{
uint32 slots = MAXFIFO - v;
while ((ALT_STATUS_WORD0 & 0x001fffff) > slots);
}
static void
WaitQueue2K(uint32 v)
{
uint32 slots = MAXFIFO - v;
while ((ALT_STATUS_WORD0 & 0x000fffff) > slots);
}
static void
WaitIdleEmpty3D()
{
while ((STATUS_WORD0 & 0x0008ffff) != 0x80000);
}
static void
WaitIdleEmpty4()
{
while ((ALT_STATUS_WORD0 & 0x00e1ffff) != 0x00e00000) ;
}
static void
WaitIdleEmpty2K()
{
while ((ALT_STATUS_WORD0 & 0x009fffff) != 0);
}
static void
Savage_GetPanelInfo()
{
SharedInfo& si = *gInfo.sharedInfo;
enum ACTIVE_DISPLAYS {
ActiveCRT = 0x01,
ActiveLCD = 0x02,
ActiveTV = 0x04,
ActiveCRT2 = 0x20,
ActiveDUO = 0x80
};
uint8 cr6b = ReadCrtcReg(0x6b);
int panelX = (ReadSeqReg(0x61) + ((ReadSeqReg(0x66) & 0x02) << 7) + 1) * 8;
int panelY = ReadSeqReg(0x69) + ((ReadSeqReg(0x6e) & 0x70) << 4) + 1;
if (panelX == 1408)
panelX = 1400;
const char* sTechnology;
if ((ReadSeqReg(0x39) & 0x03) == 0)
sTechnology = "TFT";
else if ((ReadSeqReg(0x30) & 0x01) == 0)
sTechnology = "DSTN";
else
sTechnology = "STN";
TRACE("%dx%d %s LCD panel detected %s\n", panelX, panelY, sTechnology,
cr6b & ActiveLCD ? "and active" : "but not active");
if (cr6b & ActiveLCD) {
TRACE("Limiting max video mode to %dx%d\n", panelX, panelY);
si.panelX = panelX;
si.panelY = panelY;
} else {
si.displayType = MT_CRT;
}
}
status_t
Savage_Init(void)
{
TRACE("Savage_Init()\n");
SharedInfo& si = *gInfo.sharedInfo;
WriteReg8(VGA_ENABLE + 0x8000, ReadReg8(VGA_ENABLE + 0x8000) | 0x01);
WriteMiscOutReg(ReadMiscOutReg() | 0x01);
if (si.chipType >= S3_SAVAGE4)
WriteCrtcReg(0x40, 0x01, 0x01);
WriteCrtcReg(0x11, 0x00, 0x80);
WriteCrtcReg(0x38, 0x48);
WriteCrtcReg(0x39, 0xa0);
WriteSeqReg(0x08, 0x06);
WriteCrtcReg(0x40, 0x00, 0x01);
WriteCrtcReg(0x38, 0x48);
static const uint8 RamSavage3D[] = { 8, 4, 4, 2 };
static uint8 RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 };
static const uint8 RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
static const uint8 RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 };
uint32 ramSizeMB = 0;
uint8 cr36 = ReadCrtcReg(0x36);
switch (si.chipType) {
case S3_SAVAGE_3D:
ramSizeMB = RamSavage3D[ (cr36 & 0xC0) >> 6 ];
break;
case S3_SAVAGE4:
if ((ReadCrtcReg(0x68) & 0xC0) == (0x01 << 6))
RamSavage4[1] = 8;
case S3_SAVAGE2000:
ramSizeMB = RamSavage4[ (cr36 & 0xE0) >> 5 ];
break;
case S3_SAVAGE_MX:
case S3_SUPERSAVAGE:
ramSizeMB = RamSavageMX[ (cr36 & 0x0E) >> 1 ];
break;
case S3_PROSAVAGE:
case S3_PROSAVAGE_DDR:
case S3_TWISTER:
ramSizeMB = RamSavageNB[ (cr36 & 0xE0) >> 5 ];
break;
default:
ramSizeMB = 0;
break;
}
uint32 usableMB = ramSizeMB;
if (si.chipType == S3_SAVAGE_MX && ramSizeMB > 8)
usableMB = 8;
TRACE("Savage_Init() memory size: %d MB, usable memory: %d MB\n", ramSizeMB, usableMB);
if (usableMB <= 0)
return B_ERROR;
si.videoMemSize = usableMB * 1024 * 1024;
uint32 cobSize = 0x20000;
si.cobSizeIndex = 7;
si.cobOffset = (si.videoMemSize - cobSize) & ~0x1ffff;
si.cursorOffset = (si.cobOffset - CURSOR_BYTES) & ~0xfff;
si.frameBufferOffset = 0;
si.maxFrameBufferSize = si.cursorOffset - si.frameBufferOffset;
TRACE("cobSizeIndex: %d cobSize: %d cobOffset: 0x%x\n", si.cobSizeIndex, cobSize, si.cobOffset);
TRACE("cursorOffset: 0x%x frameBufferOffset: 0x%x\n", si.cursorOffset, si.frameBufferOffset);
WriteCrtcReg(0x66, 0x02, 0x02);
snooze(10000);
WriteCrtcReg(0x66, 0x00, 0x02);
snooze(10000);
bool bDvi = false;
if (si.chipType == S3_SAVAGE4) {
WriteSeqReg(0x30, 0x00, 0x02);
if (ReadSeqReg(0x30) & 0x02 ) {
bDvi = true;
TRACE("Digital Flat Panel Detected\n");
}
}
if (S3_SAVAGE_MOBILE_SERIES(si.chipType) || S3_MOBILE_TWISTER_SERIES(si.chipType)) {
si.displayType = MT_LCD;
Savage_GetPanelInfo();
}
else if (bDvi)
si.displayType = MT_DFP;
else
si.displayType = MT_CRT;
TRACE("Display Type: %d\n", si.displayType);
WriteSeqReg(0x08, 0x06);
uint8 m = ReadSeqReg(0x11) & 0x7f;
uint8 n = ReadSeqReg(0x10);
uint8 n1 = n & 0x1f;
uint8 n2 = (n >> 5) & 0x03;
si.mclk = ((1431818 * (m + 2)) / (n1 + 2) / (1 << n2) + 50) / 100;
TRACE("Detected current MCLK value of %1.3f MHz\n", si.mclk / 1000.0);
si.colorSpaces[0] = B_CMAP8;
si.colorSpaces[1] = B_RGB16;
si.colorSpaces[2] = B_RGB32;
si.colorSpaceCount = 3;
si.bDisableHdwCursor = false;
si.bDisableAccelDraw = false;
return CreateModeList(IsModeUsable, Savage_GetEdidInfo);
}
void
Savage_SetFunctionPointers(void)
{
switch (gInfo.sharedInfo->chipType) {
case S3_SAVAGE_3D:
case S3_SAVAGE_MX:
gInfo.WaitQueue = WaitQueue3D;
gInfo.WaitIdleEmpty = WaitIdleEmpty3D;
break;
case S3_SAVAGE4:
case S3_PROSAVAGE:
case S3_SUPERSAVAGE:
case S3_PROSAVAGE_DDR:
case S3_TWISTER:
gInfo.WaitQueue = WaitQueue4;
gInfo.WaitIdleEmpty = WaitIdleEmpty4;
break;
case S3_SAVAGE2000:
gInfo.WaitQueue = WaitQueue2K;
gInfo.WaitIdleEmpty = WaitIdleEmpty2K;
break;
}
gInfo.DPMSCapabilities = Savage_DPMSCapabilities;
gInfo.GetDPMSMode = Savage_GetDPMSMode;
gInfo.SetDPMSMode = Savage_SetDPMSMode;
gInfo.LoadCursorImage = Savage_LoadCursorImage;
gInfo.SetCursorPosition = Savage_SetCursorPosition;
gInfo.ShowCursor = Savage_ShowCursor;
gInfo.FillRectangle = Savage_FillRectangle;
gInfo.FillSpan = Savage_FillSpan;
gInfo.InvertRectangle = Savage_InvertRectangle;
gInfo.ScreenToScreenBlit = Savage_ScreenToScreenBlit;
gInfo.AdjustFrame = Savage_AdjustFrame;
gInfo.ChipInit = Savage_Init;
gInfo.GetColorSpaceParams = Savage_GetColorSpaceParams;
gInfo.SetDisplayMode = Savage_SetDisplayMode;
gInfo.SetIndexedColors = Savage_SetIndexedColors;
}