* Tseng Labs ET6000, ET6100 and ET6300 graphics driver for BeOS 5.
* Copyright (c) 2003-2004, Evgeniy Vladimirovich Bobkov.
\*****************************************************************************/
#include "setmode.h"
* ATTENTION: Currently we set the graphics modes by setting the registers
* with the beforehand dumped values of the corresponding registers. So not
* all graphics modes ET6x00 chips are capable of are accessible. So it would
* be great to implement the normal algorithm of run-time computing of the
* values to set the register.
*/
typedef struct {
uint32 VisScreenWidth;
uint32 VisScreenHeight;
uint8 BitsPerPlane;
uint8 NumberGreenBits;
uint16 Frequency;
} VIDEO_MODE_INFORMATION;
* ATTENTION: Don't forget that CRTC indexed register 0x11
* bit[7] write-protects some registers.
*/
struct {
uint16 width, height, bpp, refreshRate;
uint8 clock0M, clock0N;
uint8 pci42;
uint8 crtc[64];
} clock0MN[] = {
{640, 480, 24, 75, 0x28, 0x22, 0x02,
{0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xea, 0x0c, 0xdf, 0xf0, 0x60, 0xe7, 0x04, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00}},
{640, 480, 24, 72, 0x56, 0x63, 0x00,
{0x63, 0x4f, 0x50, 0x86, 0x55, 0x9a, 0x06, 0x3e,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe8, 0x0b, 0xdf, 0xf0, 0x60, 0xe7, 0xff, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00}},
{640, 480, 24, 60, 0x28, 0x22, 0x02,
{0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xea, 0x0c, 0xdf, 0xf0, 0x60, 0xe7, 0x04, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00}},
{640, 480, 16, 75, 0x56, 0x43, 0x01,
{0x64, 0x4f, 0x4f, 0x88, 0x54, 0x9c, 0xf2, 0x1f,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe0, 0x03, 0xdf, 0xa0, 0x60, 0xdf, 0xf3, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00}},
{640, 480, 16, 72, 0x56, 0x43, 0x01,
{0x63, 0x4f, 0x50, 0x86, 0x55, 0x9a, 0x06, 0x3e,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe8, 0x0b, 0xdf, 0xa0, 0x60, 0xe7, 0xff, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00}},
{640, 480, 16, 60, 0x28, 0x41, 0x01,
{0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xea, 0x0c, 0xdf, 0xa0, 0x60, 0xe7, 0x04, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00}},
{800, 600, 24, 75, 0x79, 0x49, 0x00,
{0x7f, 0x63, 0x63, 0x83, 0x6b, 0x1b, 0x72, 0xf0,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x58, 0x0c, 0x57, 0x2c, 0x60, 0x57, 0x73, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x80}},
{800, 600, 24, 72, 0x28, 0x41, 0x00,
{0x7d, 0x63, 0x63, 0x81, 0x6d, 0x1c, 0x98, 0xf0,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7c, 0x02, 0x57, 0x2c, 0x60, 0x57, 0x99, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x80}},
{800, 600, 24, 60, 0x79, 0x49, 0x00,
{0x7f, 0x63, 0x63, 0x83, 0x6b, 0x1b, 0x72, 0xf0,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x58, 0x0c, 0x57, 0x2c, 0x60, 0x57, 0x73, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x80}},
{800, 600, 16, 75, 0x51, 0x44, 0x00,
{0x7f, 0x63, 0x63, 0x83, 0x68, 0x12, 0x6f, 0xf0,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x58, 0x0b, 0x57, 0xc8, 0x60, 0x57, 0x70, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00}},
{800, 600, 16, 72, 0x28, 0x41, 0x00,
{0x7d, 0x63, 0x63, 0x81, 0x6d, 0x1c, 0x98, 0xf0,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7c, 0x02, 0x57, 0xc8, 0x60, 0x57, 0x99, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00}},
{800, 600, 16, 60, 0x79, 0x49, 0x00,
{0x7f, 0x63, 0x63, 0x83, 0x6b, 0x1b, 0x72, 0xf0,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x58, 0x0c, 0x57, 0xc8, 0x60, 0x57, 0x73, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00}},
{1024, 768, 16, 75, 0x1f, 0x21, 0x00,
{0x9f, 0x7f, 0x7f, 0x83, 0x84, 0x90, 0x1e, 0xf5,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x83, 0xff, 0x00, 0x60, 0xff, 0x1f, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x80}},
{1024, 768, 16, 70, 0x28, 0x22, 0x00,
{0x9f, 0x7f, 0x7f, 0x83, 0x84, 0x90, 0x1e, 0xf5,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x83, 0xff, 0x00, 0x60, 0xff, 0x1f, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x80}},
{1024, 768, 16, 60, 0x6b, 0x44, 0x00,
{0xa1, 0x7f, 0x80, 0x84, 0x88, 0x99, 0x26, 0xfd,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x0a, 0xff, 0x00, 0x60, 0x04, 0x22, 0xab,
0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x80}},
};
#define CLOCK0MN (sizeof(clock0MN) / sizeof(clock0MN[0]))
__inline void et6000EnableLinearMemoryMapping(uint16 pciConfigSpace)
{
* Relocate memory via PCI Base Address 0; don't enable MMU;
* enable memory mapped registers; enable system linear memory mapping.
*/
ioSet8(pciConfigSpace+0x40, 0xf0, 0x0b);
}
static void setPCIConfigSpaceRegisters41to5E(uint16 pciConfigSpace,
VIDEO_MODE_INFORMATION *mi,
uint32 m)
{
uint8 pci415e[30] = {
0x3a, 0x00, 0x02, 0x15, 0x04, 0x40, 0x13, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8 i;
pci415e[1] = clock0MN[m].pci42;
for (i=0x41; i<0x5f; i++) {
if ((i==0x45) || ((i>0x47)&&(i<0x4e)) ||
(i==0x4e) || ((i>0x59)&&(i<0x5c)))
continue;
ioSet8(pciConfigSpace+i, 0x00, pci415e[i-0x41]);
}
if (mi->BitsPerPlane == 16) {
if (mi->NumberGreenBits == 5)
ioSet8(pciConfigSpace+0x58, 0xfd, 0x00);
else
ioSet8(pciConfigSpace+0x58, 0xfd, 0x02);
}
}
static void setMiscOutputRegister(VIDEO_MODE_INFORMATION *mi) {
uint8 MiscOutputReg;
if (mi->VisScreenHeight < 400)
MiscOutputReg = 0x80;
else if (mi->VisScreenHeight < 480)
MiscOutputReg = 0x40;
else if (mi->VisScreenHeight < 768)
MiscOutputReg = 0xc0;
else
MiscOutputReg = 0x00;
ioSet8(0x3c2, 0x00, (ioGet8(0x3cc) & 0x3f) | MiscOutputReg);
ioSet8(0x3c2, 0x00, (ioGet8(0x3cc) & 0xfc) | 0x03);
}
static void setATC(uint8 bpp) {
uint8 atc[7] = {0x21, 0x00, 0x30, 0x00, 0x00}, atc16 = 0x80;
uint8 i, atcIndexReg;
volatile uint8 f;
f = ioGet8(0x3da);
atcIndexReg = ioGet8(0x3c0) & 0xe0;
for (i = 0x10; i < 0x15; i++) {
f = ioGet8(0x3da);
ioSet8(0x3c0, 0x00, i | atcIndexReg);
ioSet8(0x3c0, 0x00, atc[i-0x10]);
}
switch (bpp) {
case 24:
atc16 |= 0x20;
break;
case 16:
atc16 |= 0x10;
break;
}
f = ioGet8(0x3da);
ioSet8(0x3c0, 0x00, 0x16 | atcIndexReg);
ioSet8(0x3c0, 0x00, atc16);
}
static void setTS(void) {
uint8 ts[7] = {0x02, 0x01, 0x0f, 0x00, 0x0e, 0x00, 0x00};
uint8 i;
for (i = 0; i < 7; i++) {
if (i == 5) continue;
ioSet8(0x3c4, 0xf8, i);
ioSet8(0x3c5, 0x00, ts[i]);
}
}
static void setGDC(void) {
uint8 gdc[9] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff};
uint8 i;
for (i = 0; i < 9; i++) {
ioSet8(0x3ce, 0xf0, i);
ioSet8(0x3cf, 0x00, gdc[i]);
}
}
static void setClock0RegNum(uint8 regNum) {
ioSet8(0x3c2, 0x00, (ioGet8(0x3cc) & 0xf3) | ((regNum & 0x03) << 2));
ioSet8(0x3d4, 0xc0, 0x34);
ioSet8(0x3d5, 0xfd, (regNum & 0x04) << 1);
}
static void setPLL(uint16 pciConfigSpace,
uint32 m)
{
uint8 regNum = 3;
uint8 clock0M = 0, clock0N = 0;
clock0M = clock0MN[m].clock0M;
clock0N = clock0MN[m].clock0N;
setClock0RegNum(regNum);
ioSet8(pciConfigSpace+0x67, 0x00, regNum);
ioSet8(pciConfigSpace+0x68, 0x00, regNum);
ioSet8(pciConfigSpace+0x69, 0x00, clock0M);
ioSet8(pciConfigSpace+0x69, 0x00, clock0N);
}
static void setCRTC(uint32 m)
{
uint8 i;
ioSet8(0x3d4, 0xc0, 0x11);
ioSet8(0x3d5, 0x7f, 0x00);
for (i = 0; i < 64; i++) {
if (((i > 0x18) && (i < 0x33)) ||
((i > 0x35) && (i < 0x3f)))
continue;
ioSet8(0x3d4, 0xc0, i);
ioSet8(0x3d5, 0x00, clock0MN[m].crtc[i]);
}
}
static uint32 et6000SetGraphicsMode(VIDEO_MODE_INFORMATION *mi,
uint16 pciConfigSpace)
{
uint8 m;
for(m = 0; m < CLOCK0MN; m++) {
if ((clock0MN[m].width == mi->VisScreenWidth) &&
(clock0MN[m].height == mi->VisScreenHeight) &&
(clock0MN[m].bpp == mi->BitsPerPlane) &&
((clock0MN[m].refreshRate-1 <= mi->Frequency) &&
(clock0MN[m].refreshRate+1 >= mi->Frequency)))
{
break;
}
}
if (m == CLOCK0MN)
return B_BAD_VALUE;
et6000EnableLinearMemoryMapping(pciConfigSpace);
setMiscOutputRegister(mi);
ioSet8(0x3d8, 0x00, 0xa0);
setPCIConfigSpaceRegisters41to5E(pciConfigSpace, mi, m);
ioSet8(0x3c6, 0x00, 0xff);
setATC(mi->BitsPerPlane);
setTS();
setGDC();
setCRTC(m);
setPLL(pciConfigSpace, m);
return B_OK;
}
status_t et6000SetMode(display_mode *mode, uint16 pciConfigSpace) {
VIDEO_MODE_INFORMATION mi;
mi.VisScreenWidth = mode->virtual_width;
mi.VisScreenHeight = mode->virtual_height;
switch (mode->space) {
case B_RGB24_LITTLE:
case B_RGB24_BIG:
mi.BitsPerPlane = 24;
mi.NumberGreenBits = 8;
break;
case B_RGB16_LITTLE:
case B_RGB16_BIG:
mi.BitsPerPlane = 16;
mi.NumberGreenBits = 6;
break;
case B_RGB15_LITTLE:
case B_RGB15_BIG:
mi.BitsPerPlane = 16;
mi.NumberGreenBits = 5;
break;
default:
return B_BAD_VALUE;
}
mi.Frequency = (uint16) (mode->timing.pixel_clock * 1000
/ (mode->timing.h_total * mode->timing.v_total));
return et6000SetGraphicsMode(&mi, pciConfigSpace);
}
status_t et6000ProposeMode(display_mode *mode, uint32 memSize) {
uint8 m, bpp;
uint16 refreshRate;
if (memSize > 0x3fe000)
memSize = 0x3fe000;
memSize -= ET6000_ACL_NEEDS_MEMORY;
switch (mode->space) {
case B_RGB24_LITTLE:
case B_RGB24_BIG:
bpp = 24;
break;
case B_RGB16_LITTLE:
case B_RGB16_BIG:
case B_RGB15_LITTLE:
case B_RGB15_BIG:
bpp = 16;
break;
default:
return B_BAD_VALUE;
}
refreshRate = (uint16) (mode->timing.pixel_clock * 1000
/ (mode->timing.h_total * mode->timing.v_total));
for(m = 0; m < CLOCK0MN; m++) {
if ((clock0MN[m].width == mode->virtual_width) &&
(clock0MN[m].height == mode->virtual_height) &&
(clock0MN[m].bpp == bpp) &&
((clock0MN[m].refreshRate-1 <= refreshRate) &&
(clock0MN[m].refreshRate+1 >= refreshRate)))
{
break;
}
}
if (m == CLOCK0MN)
return B_BAD_VALUE;
if (mode->virtual_width * mode->virtual_height * bpp / 8 > memSize)
return B_BAD_VALUE;
return B_OK;
}