/*****************************************************************************\ * 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; /* contains MCLK divider (MDIV) */ 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; /* Skip absent or read-only registers */ ioSet8(pciConfigSpace+i, 0x00, pci415e[i-0x41]); } if (mi->BitsPerPlane == 16) { if (mi->NumberGreenBits == 5) ioSet8(pciConfigSpace+0x58, 0xfd, 0x00); /* 16bpp is 5:5:5 */ else ioSet8(pciConfigSpace+0x58, 0xfd, 0x02); /* 16bpp is 5:6:5 */ } } /*****************************************************************************/ static void setMiscOutputRegister(VIDEO_MODE_INFORMATION *mi) { uint8 MiscOutputReg; if (mi->VisScreenHeight < 400) MiscOutputReg = 0x80; /* -vsync, +hsync */ else if (mi->VisScreenHeight < 480) MiscOutputReg = 0x40; /* +vsync, -hsync */ else if (mi->VisScreenHeight < 768) MiscOutputReg = 0xc0; /* -vsync, -hsync */ else MiscOutputReg = 0x00; /* +vsync, +hsync */ ioSet8(0x3c2, 0x00, (ioGet8(0x3cc) & 0x3f) | MiscOutputReg); /* Enable host access to display memory, color mode */ ioSet8(0x3c2, 0x00, (ioGet8(0x3cc) & 0xfc) | 0x03); } /*****************************************************************************/ static void setATC(uint8 bpp) { uint8 atc[7] = {0x21, 0x00, 0x30, 0x00, 0x00}, atc16 = 0x80;/// ///uint8 atc[7] = {0x01, 0x00, 0x0f, 0x00, 0x00}, atc16 = 0x80;///zzz uint8 i, atcIndexReg; volatile uint8 f; f = ioGet8(0x3da); /* Set index/data flip-flop to index mode */ atcIndexReg = ioGet8(0x3c0) & 0xe0; /* Save bits[7:5] */ for (i = 0x10; i < 0x15; i++) { f = ioGet8(0x3da); /* Set index/data flip-flop to index mode */ 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); /* Set index/data flip-flop to index mode */ 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; /* Skip absent register */ 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) { /* Set bits[1:0] of the selected CLOCK0 PLL parameters register number */ ioSet8(0x3c2, 0x00, (ioGet8(0x3cc) & 0xf3) | ((regNum & 0x03) << 2)); /* Set bit[2] of the selected CLOCK0 PLL parameters register number */ ioSet8(0x3d4, 0xc0, 0x34); ioSet8(0x3d5, 0xfd, (regNum & 0x04) << 1); } /*****************************************************************************/ static void setPLL(uint16 pciConfigSpace, uint32 m) /* mode index */ { 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) /* mode index */ { uint8 i; /* Unlock the write protection of several registers */ ioSet8(0x3d4, 0xc0, 0x11); ioSet8(0x3d5, 0x7f, 0x00); for (i = 0; i < 64; i++) { if (((i > 0x18) && (i < 0x33)) || ((i > 0x35) && (i < 0x3f))) continue; /* Skip absent or read-only registers */ 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; /* Found no entry for requested mode */ et6000EnableLinearMemoryMapping(pciConfigSpace); setMiscOutputRegister(mi); ioSet8(0x3d8, 0x00, 0xa0); /* Set the KEY for color modes */ setPCIConfigSpaceRegisters41to5E(pciConfigSpace, mi, m); ioSet8(0x3c6, 0x00, 0xff); /* Set pixel mask */ 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; /* Framebuffer must not overlap with the memory mapped registers */ 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; /* Found no entry for requested mode */ if (mode->virtual_width * mode->virtual_height * bpp / 8 > memSize) return B_BAD_VALUE; /* Not enough adapter onboard memory */ return B_OK; } /*****************************************************************************/