/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/rendition/vramdac.c,v 1.18 2002/12/11 17:23:33 dawes Exp $ */ /* * includes */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rendition.h" #include "vramdac.h" #include "vos.h" #include "v1kregs.h" #include "v2kregs.h" /* * defines */ #undef DEBUG /* directly accessable RAMDAC registers */ #define BT485_WRITE_ADDR 0x00 #define BT485_RAMDAC_DATA 0x01 #define BT485_PIXEL_MASK 0x02 #define BT485_READ_ADDR 0x03 #define BT485_CURS_WR_ADDR 0x04 #define BT485_CURS_DATA 0x05 #define BT485_COMMAND_REG_0 0x06 #define BT485_CURS_RD_ADDR 0x07 #define BT485_COMMAND_REG_1 0x08 #define BT485_COMMAND_REG_2 0x09 #define BT485_STATUS_REG 0x0a #define BT485_CURS_RAM_DATA 0x0b #define BT485_CURS_X_LOW 0x0c #define BT485_CURS_X_HIGH 0x0d #define BT485_CURS_Y_LOW 0x0e #define BT485_CURS_Y_HIGH 0x0f /* indirectly accessable ramdac registers */ #define BT485_COMMAND_REG_3 0x01 /* bits in command register 0 */ #define BT485_CR0_EXTENDED_REG_ACCESS 0x80 #define BT485_CR0_SCLK_SLEEP_DISABLE 0x40 #define BT485_CR0_BLANK_PEDESTAL 0x20 #define BT485_CR0_SYNC_ON_BLUE 0x10 #define BT485_CR0_SYNC_ON_GREEN 0x08 #define BT485_CR0_SYNC_ON_RED 0x04 #define BT485_CR0_8_BIT_DAC 0x02 #define BT485_CR0_SLEEP_ENABLE 0x01 /* bits in command register 1 */ #define BT485_CR1_24BPP 0x00 #define BT485_CR1_16BPP 0x20 #define BT485_CR1_8BPP 0x40 #define BT485_CR1_4BPP 0x60 #define BT485_CR1_1BPP 0x80 #define BT485_CR1_BYPASS_CLUT 0x10 #define BT485_CR1_565_16BPP 0x08 #define BT485_CR1_555_16BPP 0x00 #define BT485_CR1_1_TO_1_16BPP 0x04 #define BT485_CR1_2_TO_1_16BPP 0x00 #define BT485_CR1_PD7_PIXEL_SWITCH 0x02 #define BT485_CR1_PIXEL_PORT_CD 0x01 #define BT485_CR1_PIXEL_PORT_AB 0x00 /* bits in command register 2 */ #define BT485_CR2_SCLK_DISABLE 0x80 #define BT485_TEST_PATH_SELECT 0x40 #define BT485_PIXEL_INPUT_GATE 0x20 #define BT485_PIXEL_CLK_SELECT 0x10 #define BT485_INTERLACE_SELECT 0x08 #define BT485_16BPP_CLUT_PACKED 0x04 #define BT485_X_WINDOW_CURSOR 0x03 #define BT485_2_COLOR_CURSOR 0x02 #define BT485_3_COLOR_CURSOR 0x01 #define BT485_DISABLE_CURSOR 0x00 #define BT485_CURSOR_MASK 0x03 /* bits in command register 3 */ #define BT485_4BPP_NIBBLE_SWAP 0x10 #define BT485_CLOCK_DOUBLER 0x08 #define BT485_64_BY_64_CURSOR 0x04 #define BT485_32_BY_32_CURSOR 0x00 #define BT485_SIZE_MASK 0x04 /* special constants for the Brooktree BT485 RAMDAC */ #define BT485_INPUT_LIMIT 110000000 /* * local function prototypes */ static void Bt485_write_masked(IOADDRESS port, vu8 reg, vu8 mask, vu8 data); static void Bt485_write_cmd3_masked(IOADDRESS port, vu8 mask, vu8 data); #if 0 static vu8 Bt485_read_masked(IOADDRESS port, vu8 reg, vu8 mask); static vu8 Bt485_read_cmd3_masked(IOADDRESS port, vu8 mask); #endif /* * local data */ static int Cursor_size=0; /* * functions */ /* * int verite_initdac(ScrnInfoPtr pScreenInfo, vu8 bpp, vu8 doubleclock) * * Used to initialize the ramdac. Palette-bypass is dis-/enabled with respect * to the color depth, the cursor is disabled by default. If needed (i.e. if * the corresponding field in the verite_board_t struct is set), the clock doubling * is turned on. */ void verite_savedac (ScrnInfoPtr pScreenInfo) { renditionPtr pRendition = RENDITIONPTR(pScreenInfo); int iob=pRendition->board.io_base + RAMDACBASEADDR; RenditionRegPtr reg = &pRendition->saveRegs; reg->daccmd0 = verite_in8(iob+BT485_COMMAND_REG_0); reg->daccmd1 = verite_in8(iob+BT485_COMMAND_REG_1); reg->daccmd2 = verite_in8(iob+BT485_COMMAND_REG_2); verite_out8(iob+BT485_COMMAND_REG_0,reg->daccmd0 | BT485_CR0_EXTENDED_REG_ACCESS); verite_out8(iob+BT485_WRITE_ADDR, BT485_COMMAND_REG_3); reg->daccmd3 = verite_in8(iob+BT485_STATUS_REG); verite_out8(iob+BT485_COMMAND_REG_0,reg->daccmd0); } void verite_restoredac (ScrnInfoPtr pScreenInfo, RenditionRegPtr reg) { renditionPtr pRendition = RENDITIONPTR(pScreenInfo); int iob=pRendition->board.io_base + RAMDACBASEADDR; verite_out8(iob+BT485_COMMAND_REG_0, reg->daccmd0 | BT485_CR0_EXTENDED_REG_ACCESS); verite_out8(iob+BT485_COMMAND_REG_1, reg->daccmd1); verite_out8(iob+BT485_COMMAND_REG_2, reg->daccmd2); verite_out8(iob+BT485_WRITE_ADDR, BT485_COMMAND_REG_3); verite_out8(iob+BT485_STATUS_REG, reg->daccmd3); verite_out8(iob+BT485_COMMAND_REG_0, reg->daccmd0); } int verite_initdac(ScrnInfoPtr pScreenInfo, vu8 bpp, vu8 doubleclock) { renditionPtr pRendition = RENDITIONPTR(pScreenInfo); IOADDRESS iob=pRendition->board.io_base+RAMDACBASEADDR; vu8 cmd0,cmd1,cmd2; vu8 cmd3_data=0; #ifdef DEBUG ErrorF ("Rendition: Debug verite_initdac called\n"); #endif if (doubleclock) cmd3_data|=BT485_CLOCK_DOUBLER; switch (bpp) { case 1: case 4: xf86DrvMsg(pScreenInfo->scrnIndex, X_CONFIG, "color depth %d not (yet ?) supported\n", bpp); return -1; case 8: cmd0 = BT485_CR0_EXTENDED_REG_ACCESS | BT485_CR0_8_BIT_DAC; cmd1 = BT485_CR1_8BPP | BT485_CR1_PIXEL_PORT_AB; cmd2 = BT485_PIXEL_INPUT_GATE | BT485_DISABLE_CURSOR; verite_out8(iob+BT485_COMMAND_REG_0, cmd0); verite_out8(iob+BT485_COMMAND_REG_1, cmd1); verite_out8(iob+BT485_COMMAND_REG_2, cmd2); break; case 16: cmd0 = BT485_CR0_EXTENDED_REG_ACCESS | BT485_CR0_8_BIT_DAC; cmd1 = BT485_CR1_16BPP | BT485_CR1_2_TO_1_16BPP | BT485_CR1_PIXEL_PORT_AB; cmd2 = BT485_PIXEL_INPUT_GATE | BT485_DISABLE_CURSOR; if (pScreenInfo->defaultVisual == TrueColor) cmd1 |= BT485_CR1_BYPASS_CLUT; if (pScreenInfo->weight.green == 5) cmd1 |= BT485_CR1_555_16BPP; else cmd1 |= BT485_CR1_565_16BPP; verite_out8(iob+BT485_COMMAND_REG_0,cmd0); verite_out8(iob+BT485_COMMAND_REG_1,cmd1); verite_out8(iob+BT485_COMMAND_REG_2,cmd2); break; case 32: cmd0 = BT485_CR0_EXTENDED_REG_ACCESS | BT485_CR0_8_BIT_DAC; cmd1 = BT485_CR1_24BPP | BT485_CR1_PIXEL_PORT_AB; cmd2 = BT485_PIXEL_INPUT_GATE | BT485_DISABLE_CURSOR; if (pScreenInfo->defaultVisual == TrueColor) cmd1 |= BT485_CR1_BYPASS_CLUT; verite_out8(iob+BT485_COMMAND_REG_0,cmd0); verite_out8(iob+BT485_COMMAND_REG_1,cmd1); verite_out8(iob+BT485_COMMAND_REG_2,cmd2); break; default: xf86DrvMsg(pScreenInfo->scrnIndex, X_CONFIG, "Color depth not supported (%d bpp)\n", bpp); return -1; break; } verite_out8(iob+BT485_WRITE_ADDR, BT485_COMMAND_REG_3); verite_out8(iob+BT485_STATUS_REG, cmd3_data); /* Bt485_write_masked(iob, BT485_COMMAND_REG_0, 0x7f, 0x00); */ verite_out8(iob+BT485_PIXEL_MASK, 0xff); return 0; } /* * void verite_enablecursor(ScrnInfoPtr pScreenInfo, int type, int size) * * Used to enable the hardware cursor. Size indicates, whether to use no cursor * at all, a 32x32 or a 64x64 cursor. The type selects a two-color, three-color * or X-window-like cursor. Valid values are defined in vramdac.h. * */ void verite_enablecursor(ScrnInfoPtr pScreenInfo, int type, int size) { renditionPtr pRendition = RENDITIONPTR(pScreenInfo); static vu8 ctypes[]={ BT485_DISABLE_CURSOR, BT485_2_COLOR_CURSOR, BT485_3_COLOR_CURSOR, BT485_X_WINDOW_CURSOR }; static vu8 csizes[]={ BT485_32_BY_32_CURSOR, BT485_64_BY_64_CURSOR }; IOADDRESS iob=pRendition->board.io_base+RAMDACBASEADDR; #ifdef DEBUG ErrorF ("Rendition: Debug verite_enablecursor called type=0x%x\n",type); #endif /* type goes to command register 2 */ Bt485_write_masked(iob, BT485_COMMAND_REG_2, ~BT485_CURSOR_MASK, ctypes[type]); /* size is in command register 3 */ Bt485_write_cmd3_masked(iob, ~BT485_SIZE_MASK, csizes[size]); if (type) Cursor_size=(size ? 64 : 32); #ifdef DEBUG ErrorF ("Rendition: Debug verite_enablecursor Exit\n"); #endif } /* * void verite_movecursor(ScrnInfoPtr pScreenInfo, vu16 x, vu16 y, vu8 xo, vu8 yo) * * Moves the cursor to the specified location. To hide the cursor, call * this routine with x=0x0 and y=0x0. * */ void verite_movecursor(ScrnInfoPtr pScreenInfo, vu16 x, vu16 y, vu8 xo, vu8 yo) { renditionPtr pRendition = RENDITIONPTR(pScreenInfo); IOADDRESS iob=pRendition->board.io_base+RAMDACBASEADDR; x+=Cursor_size-xo; y+=Cursor_size-yo; verite_out8(iob+BT485_CURS_X_LOW, x&0xff); verite_out8(iob+BT485_CURS_X_HIGH, (x>>8)&0x0f); verite_out8(iob+BT485_CURS_Y_LOW, y&0xff); verite_out8(iob+BT485_CURS_Y_HIGH, (y>>8)&0x0f); } /* * void verite_setcursorcolor(ScrnInfoPtr pScreenInfo, vu32 bg, vu32 fg) * * Sets the color of the cursor -- should be revised for use with 3 colors! * */ void verite_setcursorcolor(ScrnInfoPtr pScreenInfo, vu32 fg, vu32 bg) { renditionPtr pRendition = RENDITIONPTR(pScreenInfo); IOADDRESS iob=pRendition->board.io_base+RAMDACBASEADDR; #ifdef DEBUG ErrorF ("Rendition: Debug verite_setcursorcolor called FG=0x%x BG=0x%x\n", fg,bg); #endif verite_out8(iob+BT485_CURS_WR_ADDR, 0x00); /* load the cursor color 0 */ verite_out8(iob+BT485_CURS_DATA, 0x00); verite_out8(iob+BT485_CURS_DATA, 0x00); verite_out8(iob+BT485_CURS_DATA, 0x00); /* load the cursor color 1 */ verite_out8(iob+BT485_CURS_DATA, (fg>>16) & 0xff); verite_out8(iob+BT485_CURS_DATA, (fg>>8) & 0xff); verite_out8(iob+BT485_CURS_DATA, fg&0xff ); /* * The V2xxx and the V1xxx with external BT485 behave differently. * If we set color 2 to fg both work correctly. */ /* load the cursor color 2 */ verite_out8(iob+BT485_CURS_DATA, (fg>>16) & 0xff); verite_out8(iob+BT485_CURS_DATA, (fg>>8) & 0xff); verite_out8(iob+BT485_CURS_DATA, fg & 0xff); /* load the cursor color 3 */ verite_out8(iob+BT485_CURS_DATA, (bg>>16)&0xff ); verite_out8(iob+BT485_CURS_DATA, (bg>>8)&0xff ); verite_out8(iob+BT485_CURS_DATA, bg&0xff ); } /* * Oh god, this code is quite a mess ... should be re-written soon. * But for now I'm happy it works ;) * */ void verite_loadcursor(ScrnInfoPtr pScreenInfo, vu8 size, vu8 *cursorimage) { int c, bytes, row; vu8 *src = cursorimage; renditionPtr pRendition = RENDITIONPTR(pScreenInfo); IOADDRESS iob=pRendition->board.io_base+RAMDACBASEADDR; vu8 tmp; vu8 memend; /* Added for byte-swap fix */ #ifdef DEBUG ErrorF ("Rendition: Debug verite_loadcursor called\n"); #endif if (NULL == cursorimage) return; /* Following two lines added for the byte-swap fix */ memend = verite_in8(pRendition->board.io_base + MEMENDIAN); verite_out8(pRendition->board.io_base + MEMENDIAN, MEMENDIAN_HW); size&=1; if (size) bytes=64; else bytes=32; bytes=(bytes*bytes)>>3; if (pRendition->board.chip == V1000_DEVICE) { /* now load the cursor data into the cursor ram */ tmp=verite_in8(iob+BT485_COMMAND_REG_0)&0x7f; verite_out8(iob+BT485_COMMAND_REG_0, tmp|0x80); verite_out8(iob+BT485_WRITE_ADDR, BT485_COMMAND_REG_3); tmp=verite_in8(iob+BT485_STATUS_REG)&0xf8; verite_out8(iob+BT485_STATUS_REG, tmp|(size<<2)); verite_out8(iob+BT485_WRITE_ADDR, 0x00); /* output cursor image */ src=cursorimage; /* First plane data */ for (c=0; cboard.hwcursor_membase); /* First plane data */ for (row=0; row<64; row++) for (c=0, src=cursorimage+1+16*row; c<8; c++, src+=2) verite_write_memory8(pRendition->board.vmem_base, 16*(63-row)+c, (c&1)?(*(src-2)):(*(src+2))); /* Second plane data */ for (row=0; row<64; row++) for (c=0, src=cursorimage+16*row; c<8; c++, src+=2) verite_write_memory8(pRendition->board.vmem_base, 8+16*(63-row)+c, (c&1)?(*(src-2)):(*(src+2))); } /* Following line added for the byte-swap fix */ verite_out8(pRendition->board.io_base + MEMENDIAN, memend); } /* NOTE: count is the actual number of colors decremented by 1 */ void verite_setpalette(ScrnInfoPtr pScreenInfo, int numColors, int *indices, LOCO *colors, VisualPtr pVisual) { renditionPtr pRendition = RENDITIONPTR(pScreenInfo); IOADDRESS iob=pRendition->board.io_base; vu32 crtc_status; int i, index; #ifdef DEBUG ErrorF ("Rendition: Debug verite_setpalette called\n"); #endif while (1) { crtc_status=verite_in32(iob+CRTCSTATUS); if (crtc_status & CRTCSTATUS_VERT_SYNC) break; }; iob+=RAMDACBASEADDR; for (i = 0; i < numColors; i++) { index = indices[i]; verite_out8(iob+BT485_WRITE_ADDR, index); verite_out8(iob+BT485_RAMDAC_DATA, colors[index].red); verite_out8(iob+BT485_RAMDAC_DATA, colors[index].green); verite_out8(iob+BT485_RAMDAC_DATA, colors[index].blue); } } /* * local functions */ /* * static void Bt485_write_masked(IOADDRESS port, vu8 reg, vu8 mask, vu8 data) * * */ static void Bt485_write_masked(IOADDRESS port, vu8 reg, vu8 mask, vu8 data) { vu8 tmp; tmp=verite_in8(port+reg)&mask; verite_out8(port+reg, tmp|data); } /* * static void Bt485_write_cmd3_masked(IOADDRESS port, vu8 mask, vu8 data) * * */ static void Bt485_write_cmd3_masked(IOADDRESS port, vu8 mask, vu8 data) { /* * Bt485_write_masked(port, BT485_COMMAND_REG_0, 0x7f, 0x80); */ verite_out8(port+BT485_WRITE_ADDR, BT485_COMMAND_REG_3); Bt485_write_masked(port, BT485_STATUS_REG, mask, data); /* * Bt485_write_masked(port, BT485_COMMAND_REG_0, 0x7f, 0x00); */ } #if 0 /* * static vu8 Bt485_read_masked(IOADDRESS port, vu8 reg, vu8 mask) * * */ static vu8 Bt485_read_masked(IOADDRESS port, vu8 reg, vu8 mask) { return verite_in8(port+reg)&mask; } /* * static vu8 Bt485_read_cmd3_masked(IOADDRESS port, vu8 mask) * * */ static vu8 Bt485_read_cmd3_masked(IOADDRESS port, vu8 mask) { vu8 value; Bt485_write_masked(port, BT485_COMMAND_REG_0, 0x7f, 0x80); verite_out8(port+BT485_WRITE_ADDR, BT485_COMMAND_REG_3); value=Bt485_read_masked(port, BT485_STATUS_REG, mask); Bt485_write_masked(port, BT485_COMMAND_REG_0, 0x7f, 0x00); return value; } #endif /* * end of file vramdac.c */