s3_Ti.c revision a9060c92
1/* 2 * Copyright 2001 Ani Joshi <ajoshi@unixbox.com> 3 * 4 * XFree86 4.x driver for S3 chipsets 5 * 6 * 7 * Permission to use, copy, modify, distribute, and sell this software and its 8 * documentation for any purpose is hereby granted without fee, provided that 9 * the above copyright notice appear in all copies and that both that copyright 10 * notice and this permission notice appear in supporting documentation and 11 * that the name of Ani Joshi not be used in advertising or 12 * publicity pertaining to distribution of the software without specific, 13 * written prior permission. Ani Joshi makes no representations 14 * about the suitability of this software for any purpose. It is provided 15 * "as-is" without express or implied warranty. 16 * 17 * ANI JOSHI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 19 * EVENT SHALL ANI JOSHI BE LIABLE FOR ANY SPECIAL, INDIRECT OR 20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 23 * PERFORMANCE OF THIS SOFTWARE. 24 * 25 * 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include "xf86.h" 33#include "xf86_OSproc.h" 34#include <X11/Xos.h> 35 36#include "compiler.h" 37 38#include "TI.h" 39 40#include "s3.h" 41 42 43#define TI_WRITE_ADDR 0x3C8 /* CR55 low bit == 0 */ 44#define TI_RAMDAC_DATA 0x3C9 /* CR55 low bit == 0 */ 45#define TI_PIXEL_MASK 0x3C6 /* CR55 low bit == 0 */ 46#define TI_READ_ADDR 0x3C7 /* CR55 low bit == 0 */ 47#define TI_INDEX_REG 0x3C6 /* CR55 low bit == 1 */ 48#define TI_DATA_REG 0x3C7 /* CR55 low bit == 1 */ 49 50#define TIDAC_output_clock_select 0x1b 51#define TIDAC_auxiliary_ctrl 0x29 52#define TIDAC_general_io_ctrl 0x2a 53#define TIDAC_general_io_data 0x2b 54#define TIDAC_cursor_color_0_red 0x23 55#define TIDAC_cursor_color_0_green 0x24 56#define TIDAC_cursor_color_0_blue 0x25 57#define TIDAC_cursor_color_1_red 0x26 58#define TIDAC_cursor_color_1_green 0x27 59#define TIDAC_cursor_color_1_blue 0x28 60#define TIDAC_cursor_x_low 0x00 61#define TIDAC_cursor_x_high 0x01 62#define TIDAC_cursor_y_low 0x02 63#define TIDAC_cursor_y_high 0x03 64#define TIDAC_cursor_ram_addr_low 0x08 65#define TIDAC_cursor_ram_addr_high 0x09 66#define TIDAC_cursor_ram_data 0x0a 67 68 69#define TI_REF_FREQ 14.31818 /* 3025 only */ 70 71#undef FREQ_MIN 72#define FREQ_MIN 12000 73#define FREQ_MAX 220000 74 75 76 77void S3OutTiIndReg(ScrnInfoPtr pScrn, CARD32 reg, unsigned char mask, 78 unsigned char data) 79{ 80 S3Ptr pS3 = S3PTR(pScrn); 81 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 82 unsigned char tmp, tmp1, tmp2 = 0x00; 83 84 outb(vgaCRIndex, 0x55); 85 tmp = inb(vgaCRReg) & 0xfc; 86 outb(vgaCRReg, tmp | 0x01); 87 tmp1 = inb(TI_INDEX_REG); 88 outb(TI_INDEX_REG, reg); 89 90 if (mask != 0x00) 91 tmp2 = inb(TI_DATA_REG) & mask; 92 outb(TI_DATA_REG, tmp2 | data); 93 94 outb(TI_INDEX_REG, tmp1); 95 outb(vgaCRReg, tmp); 96} 97 98 99static unsigned char S3InTiIndReg(ScrnInfoPtr pScrn, CARD32 reg) 100{ 101 S3Ptr pS3 = S3PTR(pScrn); 102 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 103 unsigned char tmp, tmp1, ret; 104 105 outb(vgaCRIndex, 0x55); 106 tmp = inb(vgaCRReg) & 0xfc; 107 outb(vgaCRReg, tmp | 0x01); 108 tmp1 = inb(TI_INDEX_REG); 109 outb(TI_INDEX_REG, reg); 110 111 ret = inb(TI_DATA_REG); 112 113 outb(TI_INDEX_REG, tmp1); 114 outb(vgaCRReg, tmp); 115 116 return ret; 117} 118 119 120Bool S3TiDACProbe(ScrnInfoPtr pScrn) 121{ 122 S3Ptr pS3 = S3PTR(pScrn); 123 int found = 0; 124 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 125 unsigned char cr55, cr45, cr43, cr5c; 126 unsigned char TIndx, TIndx2, TIdata; 127 128 if (!S3_964_SERIES()) 129 return FALSE; 130 131 outb(vgaCRIndex, 0x43); 132 cr43 = inb(vgaCRReg); 133 outb(vgaCRReg, cr43 & ~0x02); 134 135 outb(vgaCRIndex, 0x45); 136 cr45 = inb(vgaCRReg); 137 138 outb(vgaCRIndex, 0x55); 139 cr55 = inb(vgaCRReg); 140 outb(vgaCRReg, (cr55 & 0xfc) | 0x01); 141 142 TIndx = inb(TI_INDEX_REG); 143 outb(TI_INDEX_REG, TIDAC_id); 144 if(inb(TI_DATA_REG) == 0x20) { 145 found = TI3020_RAMDAC; 146 cr43 &= ~0x02; 147 cr45 &= ~0x20; 148 } else { 149 outb(vgaCRIndex, 0x5c); 150 cr5c = inb(vgaCRReg); 151 outb(vgaCRReg, cr5c & 0xdf); 152 TIndx2 = inb(TI_INDEX_REG); 153 outb(TI_INDEX_REG, TIDAC_ind_curs_ctrl); 154 TIdata = inb(TI_DATA_REG); 155 outb(TI_DATA_REG, TIdata & 0x7f); 156 157 outb(TI_INDEX_REG, TIDAC_id); 158 if (inb(TI_DATA_REG) == 0x25) { 159 found = TI3025_RAMDAC; 160 cr43 &= ~0x02; 161 cr45 &= ~0x20; 162 } 163 164 outb(TI_INDEX_REG, TIDAC_ind_curs_ctrl); 165 outb(TI_DATA_REG, TIdata); 166 outb(TI_INDEX_REG, TIndx2); 167 outb(vgaCRIndex, 0x5c); 168 outb(vgaCRReg, cr5c); 169 } 170 171 outb(TI_INDEX_REG, TIndx); 172 outb(vgaCRIndex, 0x55); 173 outb(vgaCRReg, cr55); 174 175 outb(vgaCRIndex, 0x45); 176 outb(vgaCRReg, cr45); 177 178 outb(vgaCRIndex, 0x43); 179 outb(vgaCRReg, cr43); 180 181 if (found) { 182 RamDacInit(pScrn, pS3->RamDacRec); 183 pS3->RamDac = RamDacHelperCreateInfoRec(); 184 pS3->RamDac->RamDacType = found; 185 return TRUE; 186 } 187 188 return FALSE; 189} 190 191 192void S3TiDAC_Save(ScrnInfoPtr pScrn) 193{ 194 S3Ptr pS3 = S3PTR(pScrn); 195 S3RegPtr save = &pS3->SavedRegs; 196 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 197 198 if (pS3->RamDac->RamDacType == TI3025_RAMDAC) { 199 unsigned char cr5c; 200 201 outb(vgaCRIndex, 0x5c); 202 cr5c = inb(vgaCRReg); 203 outb(vgaCRReg, cr5c & 0xdf); 204 205 save->dacregs[TIDAC_ind_curs_ctrl] = 206 S3InTiIndReg(pScrn, TIDAC_ind_curs_ctrl); 207 S3OutTiIndReg(pScrn, TIDAC_ind_curs_ctrl, 0x7f, 0x00); 208 } 209 210 save->dacregs[TIDAC_true_color_ctrl] = 211 S3InTiIndReg(pScrn, TIDAC_true_color_ctrl); 212 save->dacregs[TIDAC_multiplex_ctrl] = 213 S3InTiIndReg(pScrn, TIDAC_multiplex_ctrl); 214 save->dacregs[TIDAC_clock_select] = 215 S3InTiIndReg(pScrn, TIDAC_clock_select); 216 save->dacregs[TIDAC_output_clock_select] = 217 S3InTiIndReg(pScrn, TIDAC_output_clock_select); 218 save->dacregs[TIDAC_general_ctrl] = 219 S3InTiIndReg(pScrn, TIDAC_general_ctrl); 220 save->dacregs[TIDAC_auxiliary_ctrl] = 221 S3InTiIndReg(pScrn, TIDAC_auxiliary_ctrl); 222 S3OutTiIndReg(pScrn, TIDAC_general_io_ctrl, 0x00, 0x1f); 223 save->dacregs[TIDAC_general_io_data] = 224 S3InTiIndReg(pScrn, TIDAC_general_io_data); 225 226 if (pS3->RamDac->RamDacType == TI3025_RAMDAC) { 227 save->dacregs[0x0e] = S3InTiIndReg(pScrn, 0x0e); 228 save->dacregs[TIDAC_misc_ctrl] = 229 S3InTiIndReg(pScrn, TIDAC_misc_ctrl); 230 S3OutTiIndReg(pScrn, TIDAC_pll_addr, 0x00, 0x00); 231 save->dacregs[0x40] = S3InTiIndReg(pScrn, TIDAC_pll_pixel_data); 232 S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00, 233 save->dacregs[0x40]); 234 save->dacregs[0x41] = S3InTiIndReg(pScrn, TIDAC_pll_pixel_data); 235 S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00, 236 save->dacregs[0x41]); 237 save->dacregs[0x42] = S3InTiIndReg(pScrn, TIDAC_pll_pixel_data); 238 S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00, 239 save->dacregs[0x42]); 240 save->dacregs[0x43] = S3InTiIndReg(pScrn, TIDAC_pll_memory_data); 241 S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00, 242 save->dacregs[0x43]); 243 save->dacregs[0x44] = S3InTiIndReg(pScrn, TIDAC_pll_memory_data); 244 S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00, 245 save->dacregs[0x44]); 246 save->dacregs[0x45] = S3InTiIndReg(pScrn, TIDAC_pll_memory_data); 247 S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00, 248 save->dacregs[0x45]); 249 save->dacregs[0x46] = S3InTiIndReg(pScrn, TIDAC_pll_loop_data); 250 S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00, 251 save->dacregs[0x46]); 252 save->dacregs[0x47] = S3InTiIndReg(pScrn, TIDAC_pll_loop_data); 253 S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00, 254 save->dacregs[0x47]); 255 save->dacregs[0x48] = S3InTiIndReg(pScrn, TIDAC_pll_loop_data); 256 S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00, 257 save->dacregs[0x48]); 258 } 259} 260 261 262void S3TiDAC_Restore(ScrnInfoPtr pScrn) 263{ 264 S3Ptr pS3 = S3PTR(pScrn); 265 S3RegPtr restore = &pS3->SavedRegs; 266 267 S3OutTiIndReg(pScrn, TIDAC_true_color_ctrl, 0x00, 268 restore->dacregs[TIDAC_true_color_ctrl]); 269 S3OutTiIndReg(pScrn, TIDAC_multiplex_ctrl, 0x00, 270 restore->dacregs[TIDAC_multiplex_ctrl]); 271 S3OutTiIndReg(pScrn, TIDAC_clock_select, 0x00, 272 restore->dacregs[TIDAC_clock_select]); 273 S3OutTiIndReg(pScrn, TIDAC_output_clock_select, 0x00, 274 restore->dacregs[TIDAC_output_clock_select]); 275 S3OutTiIndReg(pScrn, TIDAC_general_ctrl, 0x00, 276 restore->dacregs[TIDAC_general_ctrl]); 277 S3OutTiIndReg(pScrn, TIDAC_auxiliary_ctrl, 0x00, 278 restore->dacregs[TIDAC_auxiliary_ctrl]); 279 S3OutTiIndReg(pScrn, TIDAC_general_io_ctrl, 0x00, 0x1f); 280 S3OutTiIndReg(pScrn, TIDAC_general_io_data, 0x00, 281 restore->dacregs[TIDAC_general_io_data]); 282 if (pS3->RamDac->RamDacType == TI3025_RAMDAC) { 283 S3OutTiIndReg(pScrn, TIDAC_pll_addr, 0x00, 284 restore->dacregs[TIDAC_pll_addr]); 285 S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00, 286 restore->dacregs[0x40]); 287 S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00, 288 restore->dacregs[0x41]); 289 S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00, 290 restore->dacregs[0x42]); 291 292 S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00, 293 restore->dacregs[0x43]); 294 S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00, 295 restore->dacregs[0x44]); 296 S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00, 297 restore->dacregs[0x45] | 0x80); 298 299 S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00, 300 restore->dacregs[0x46]); 301 S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00, 302 restore->dacregs[0x47]); 303 S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00, 304 restore->dacregs[0x48]); 305 306 S3OutTiIndReg(pScrn, 0x0e, 0x00, restore->dacregs[0x0e]); 307 S3OutTiIndReg(pScrn, TIDAC_misc_ctrl, 0x00, 308 restore->dacregs[TIDAC_misc_ctrl]); 309 } 310 311 S3OutTiIndReg(pScrn, TIDAC_ind_curs_ctrl, 0x00, 312 restore->dacregs[TIDAC_ind_curs_ctrl]); 313} 314 315 316void S3TiDAC_PreInit(ScrnInfoPtr pScrn) 317{ 318 S3Ptr pS3 = S3PTR(pScrn); 319 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 320 int mclk, m, n, p, mcc, cr5c; 321 322 outb(vgaCRIndex, 0x5c); 323 cr5c = inb(vgaCRReg); 324 outb(vgaCRReg, cr5c & 0xdf); 325 326 S3OutTiIndReg(pScrn, TIDAC_pll_addr, 0x00, 0x00); 327 n = S3InTiIndReg(pScrn, TIDAC_pll_memory_data) & 0x7f; 328 S3OutTiIndReg(pScrn, TIDAC_pll_addr, 0x00, 0x01); 329 m = S3InTiIndReg(pScrn, TIDAC_pll_memory_data) & 0x7f; 330 S3OutTiIndReg(pScrn, TIDAC_pll_addr, 0x00, 0x02); 331 p = S3InTiIndReg(pScrn, TIDAC_pll_memory_data) & 0x03; 332 mcc = S3InTiIndReg(pScrn, TIDAC_clock_ctrl); 333 if (mcc & 0x08) 334 mcc = (mcc & 0x07) * 2 + 2; 335 else 336 mcc = 1; 337 338 mclk = ((1431818 * ((m+2) * 8)) / (n+2) / (1 << p) / mcc + 50) / 100; 339 pS3->mclk = mclk; 340 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "MCLK %1.3f MHz\n", 341 mclk / 1000.0); 342 343 outb(vgaCRIndex, 0x5c); 344 outb(vgaCRReg, cr5c); 345} 346 347 348static void S3TiDACCalcNMP(long freq, int *calc_n, int *calc_m, int *calc_p) 349{ 350 double ffreq; 351 int n, m, p; 352 int best_n=32, best_m=32; 353 double diff, mindiff; 354 355 if (freq < FREQ_MIN) 356 ffreq = FREQ_MIN / 1000.0; 357 else if (freq > FREQ_MAX) 358 ffreq = FREQ_MAX / 1000.0; 359 else 360 ffreq = freq / 1000.0; 361 362 for (p=0; p<4 && ffreq<110.0; p++) 363 ffreq *= 2; 364#if FREQ_MIN < 110000/8 365 if (p == 4) { 366 ffreq /= 2; 367 p--; 368 } 369#endif 370 371 ffreq /= TI_REF_FREQ; 372 373 mindiff = ffreq; 374 375 for (n=1; n<=(int)(TI_REF_FREQ/0.5 - 2); n++) { 376 m = (int)(ffreq * (n+2) / 8.0 + 0.5) - 2; 377 if (m < 1) 378 m = 1; 379 else if (m > 127) 380 m = 127; 381 382 diff = ((m+2) * 8) / (n+2.0) - ffreq; 383 if (diff < 0) 384 diff = -diff; 385 386 if (diff < mindiff) { 387 mindiff = diff; 388 best_n = n; 389 best_m = m; 390 } 391 } 392 393 *calc_n = best_n; 394 *calc_m = best_m; 395 *calc_p = p; 396} 397 398 399static void S3TiDACProgramClock(ScrnInfoPtr pScrn, int clk, 400 unsigned char n, unsigned char m, 401 unsigned char p) 402{ 403 S3OutTiIndReg(pScrn, TIDAC_pll_addr, 0x00, 0x00); 404 405 if (clk != TIDAC_pll_memory_data) { 406 S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00, n); 407 S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00, m); 408 S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00, p | 0x08); 409 410 S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00, 0x01); 411 S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00, 0x01); 412 S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00, p > 0 ? p : 1); 413 S3OutTiIndReg(pScrn, TIDAC_misc_ctrl, 0x00, 0x80 | 0x40 | 0x04); 414 415 S3OutTiIndReg(pScrn, TIDAC_clock_select, 0x00, 0x05); 416 } else { 417 S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00, n); 418 S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00, m); 419 S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00, p | 0x80); 420 } 421} 422 423 424static void S3TiDACSetClock(ScrnInfoPtr pScrn, long freq, int clk) 425{ 426 int m, n, p; 427 428 S3TiDACCalcNMP(freq, &n, &m, &p); 429 430 S3TiDACProgramClock(pScrn, clk, n, m, p); 431} 432 433 434 435void S3TiDAC_Init(ScrnInfoPtr pScrn, DisplayModePtr mode) 436{ 437 S3Ptr pS3 = S3PTR(pScrn); 438 vgaHWPtr hwp = VGAHWPTR(pScrn); 439 vgaRegPtr pVga = &hwp->ModeReg; 440 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 441 unsigned char tmp, tmp1, tmp2; 442 443 S3TiDACSetClock(pScrn, mode->Clock, 2); 444 outb(vgaCRIndex, 0x42); 445 tmp = inb(vgaCRReg) & 0xf0; 446 outb(vgaCRReg, tmp | 0x02); 447 usleep(150000); 448 449 outb(0x3c4, 1); 450 tmp2 = inb(0x3c5); 451 outb(0x3c5, tmp2 | 0x20); /* blank */ 452 453 tmp = pVga->MiscOutReg; 454 pVga->MiscOutReg |= 0xc0; 455 tmp1 = 0x00; 456 if (!(tmp & 0x80)) 457 tmp1 |= 0x02; 458 if (!(tmp & 0x40)) 459 tmp1 |= 0x01; 460 461 S3OutTiIndReg(pScrn, TIDAC_general_ctrl, 0x00, tmp1); 462 S3OutTiIndReg(pScrn, 0x0e, 0x00, 0x00); 463 464 /* XXX do 3020 input_clock_sel */ 465 466 outb(vgaCRIndex, 0x65); 467 /* XXX 3025 */ 468 outb(vgaCRReg, 0x00); 469 470 /* XXX 3025 */ 471 outb(vgaCRIndex, 0x40); 472 outb(vgaCRReg, 0x11); 473 outb(vgaCRIndex, 0x55); 474 outb(vgaCRReg, 0x00); 475 476 if (pScrn->bitsPerPixel > 8) 477 S3OutTiIndReg(pScrn, TIDAC_auxiliary_ctrl, 0x00, 0x00); 478 else 479 S3OutTiIndReg(pScrn, TIDAC_auxiliary_ctrl, 0x00, 0x01); 480 481 switch (pScrn->depth) { 482 case 8: 483 S3OutTiIndReg(pScrn, TIDAC_output_clock_select, 0x00, 484 0x4b); 485 outb(vgaCRIndex, 0x66); 486 tmp = inb(vgaCRReg); 487 if (mode->Clock > 80000) 488 outb(vgaCRReg, (tmp & 0xf8) | 0x02); 489 else 490 outb(vgaCRReg, (tmp & 0xf8) | 0x03); 491 break; 492 case 16: 493 S3OutTiIndReg(pScrn, TIDAC_output_clock_select, 0x00, 494 0x4a); 495 outb(vgaCRIndex, 0x66); 496 tmp = inb(vgaCRReg); 497 if (mode->Clock > 80000) 498 outb(vgaCRReg, (tmp & 0xf8) | 0x01); 499 else 500 outb(vgaCRReg, (tmp & 0xf8) | 0x02); 501 break; 502 case 24: 503 S3OutTiIndReg(pScrn, TIDAC_output_clock_select, 0x00, 504 (0x40 | 0x08 | 0x01)); 505 outb(vgaCRIndex, 0x66); 506 tmp = inb(vgaCRReg); 507 if (mode->Clock > 80000) 508 outb(vgaCRReg, (tmp & 0xf8) | 0x00); 509 else 510 outb(vgaCRReg, (tmp & 0xf8) | 0x01); 511 break; 512 } 513 514 outb(vgaCRIndex, 0x58); 515 tmp = inb(vgaCRReg); 516 outb(vgaCRReg, (tmp & 0xbf) | 0x40); 517 518 switch(pScrn->depth) { 519 case 8: 520 S3OutTiIndReg(pScrn, TIDAC_true_color_ctrl, 0x00, 0x80); 521 S3OutTiIndReg(pScrn, TIDAC_multiplex_ctrl, 0x00, 0x1c); 522 break; 523 case 15: 524 S3OutTiIndReg(pScrn, TIDAC_true_color_ctrl, 0x00, 0x4c); 525 S3OutTiIndReg(pScrn, TIDAC_multiplex_ctrl, 0x00, 0x04); 526 S3OutTiIndReg(pScrn, TIDAC_key_ctrl, 0x00, 0x01); 527 break; 528 case 16: 529 S3OutTiIndReg(pScrn, TIDAC_true_color_ctrl, 0x00, 0x4d); 530 S3OutTiIndReg(pScrn, TIDAC_multiplex_ctrl, 0x00, 0x04); 531 S3OutTiIndReg(pScrn, TIDAC_key_ctrl, 0x00, 0x01); 532 break; 533 case 24: 534 S3OutTiIndReg(pScrn, TIDAC_true_color_ctrl, 0x00, 0x4e); 535 S3OutTiIndReg(pScrn, TIDAC_multiplex_ctrl, 0x00, 0x04); 536 S3OutTiIndReg(pScrn, TIDAC_key_ctrl, 0x00, 0x01); 537 break; 538 } 539 540 S3OutTiIndReg(pScrn, TIDAC_general_io_ctrl, 0x00, 0x1f); 541 S3OutTiIndReg(pScrn, TIDAC_general_io_data, 0x00, 0x01); 542 S3OutTiIndReg(pScrn, TIDAC_general_io_ctrl, 0x00, 0x00); 543 S3OutTiIndReg(pScrn, TIDAC_misc_ctrl, 0xf0, (0x04 | 0x08)); 544 545 outb(vgaCRIndex, 0x6d); 546 if (pS3->s3Bpp == 1) 547 if (mode->Clock > 80000) 548 outb(vgaCRReg, 0x02); 549 else 550 outb(vgaCRReg, 0x03); 551 else if (pS3->s3Bpp == 2) 552 if (mode->Clock > 80000) 553 outb(vgaCRReg, 0x00); 554 else 555 outb(vgaCRReg, 0x01); 556 else 557 outb(vgaCRReg, 0x00); 558 559 S3OutTiIndReg(pScrn, TIDAC_sense_test, 0x00, 0x00); 560 561 if (pS3->s3Bpp > 1) 562 { 563 int j; 564 565 outb(0x3c6, 0xff); 566 outb(0x3c8, 0x00); 567 for(j=0; j<768; j++) { 568 outb(0x3c9, j); 569 outb(0x3c9, j); 570 outb(0x3c9, j); 571 } 572 } 573 574 outb(0x3c4, 1); 575 outb(0x3c5, tmp2); /* unblank */ 576} 577 578 579void S3TiLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies, LOCO *colors, 580 VisualPtr pVisual) 581{ 582 int i; 583 584 outb(0x3c6, 0xff); 585 outb(0x3c8, 0x00); 586 587 for (i=0; i<768; i++) { 588 outb(0x3c9, i); 589 usleep(1000); 590 outb(0x3c9, i); 591 usleep(1000); 592 outb(0x3c9, i); 593 usleep(1000); 594 } 595} 596 597 598 599/* hardware cursor */ 600 601static void S3TiSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) 602{ 603 S3Ptr pS3 = S3PTR(pScrn); 604 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 605 606 /* unlock sys regs */ 607 outb(vgaCRIndex, 0x39); 608 outb(vgaCRReg, 0xa5); 609 610 S3OutTiIndReg(pScrn, TIDAC_cursor_color_0_red, 0x00, 611 (bg & 0x00FF0000) >> 16); 612 S3OutTiIndReg(pScrn, TIDAC_cursor_color_0_green, 0x00, 613 (bg & 0x0000FF00) >> 8); 614 S3OutTiIndReg(pScrn, TIDAC_cursor_color_0_blue, 0x00, 615 (bg & 0x000000FF)); 616 617 S3OutTiIndReg(pScrn, TIDAC_cursor_color_1_red, 0x00, 618 (fg & 0x00FF0000) >> 16); 619 S3OutTiIndReg(pScrn, TIDAC_cursor_color_1_green, 0x00, 620 (fg & 0x0000FF00) >> 8); 621 S3OutTiIndReg(pScrn, TIDAC_cursor_color_1_blue, 0x00, 622 (fg & 0x000000FF)); 623 624} 625 626 627static void S3TiSetCursorPosition(ScrnInfoPtr pScrn, int x, int y) 628{ 629 S3Ptr pS3 = S3PTR(pScrn); 630 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 631 632 /* unlock sys regs */ 633 outb(vgaCRIndex, 0x39); 634 outb(vgaCRReg, 0xa5); 635 636 S3OutTiIndReg(pScrn, TIDAC_cursor_x_low, 0x00, x & 0xff); 637 S3OutTiIndReg(pScrn, TIDAC_cursor_x_high, 0x00, (x >> 8) & 0x0f); 638 S3OutTiIndReg(pScrn, TIDAC_cursor_y_low, 0x00, y & 0xff); 639 S3OutTiIndReg(pScrn, TIDAC_cursor_y_high, 0x00, (y >> 8) & 0x0f); 640} 641 642 643static void S3TiHideCursor(ScrnInfoPtr pScrn) 644{ 645 S3Ptr pS3 = S3PTR(pScrn); 646 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 647 648 /* unlock sys regs */ 649 outb(vgaCRIndex, 0x39); 650 outb(vgaCRReg, 0xa5); 651 652 S3OutTiIndReg(pScrn, TIDAC_ind_curs_ctrl, (unsigned char) 653 ~(0x40 | 0x10), 0x00); 654} 655 656 657static void S3TiShowCursor(ScrnInfoPtr pScrn) 658{ 659 S3Ptr pS3 = S3PTR(pScrn); 660 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 661 unsigned char tmp; 662 663 /* unlock sys regs */ 664 outb(vgaCRIndex, 0x39); 665 outb(vgaCRReg, 0xa5); 666 667 outb(vgaCRIndex, 0x55); 668 tmp = inb(vgaCRReg) & 0xdf; 669 outb(vgaCRReg, tmp | 0x20); 670 671 outb(vgaCRIndex, 0x45); 672 tmp = inb(vgaCRReg) & 0xdf; 673 outb(vgaCRReg, tmp | 0x20); 674 675 S3OutTiIndReg(pScrn, TIDAC_ind_curs_ctrl, (unsigned char) 676 ~(0x40 | 0x10), (0x40 | 0x10)); 677} 678 679 680static void S3TiLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image) 681{ 682 S3Ptr pS3 = S3PTR(pScrn); 683 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 684 unsigned char tmp, tmp1; 685 register int i; 686#if 0 687 register unsigned char *mask = image + 1; 688#endif 689 690 /* unlock sys regs */ 691 outb(vgaCRIndex, 0x39); 692 outb(vgaCRReg, 0xa5); 693 694 outb(vgaCRIndex, 0x55); 695 tmp = inb(vgaCRReg) & 0xfc; 696 outb(vgaCRReg, tmp | 0x01); 697 tmp1 = inb(TI_INDEX_REG); 698 699 outb(TI_INDEX_REG, TIDAC_cursor_ram_addr_low); 700 outb(TI_DATA_REG, 0x00); 701 outb(TI_INDEX_REG, TIDAC_cursor_ram_addr_high); 702 outb(TI_DATA_REG, 0x00); 703 outb(TI_INDEX_REG, TIDAC_cursor_ram_data); 704 705#if 0 706 for (i=0; i<512; i++, mask+=2) 707 outb(TI_DATA_REG, *mask); 708 for (i=0; i<512; i++, image+=2) 709 outb(TI_DATA_REG, *image); 710#else 711 for (i=0; i<1024; i++) { 712 outb(TI_DATA_REG, *image); 713 image++; 714 } 715#endif 716 717 outb(TI_INDEX_REG, tmp1); 718 719 outb(vgaCRIndex, 0x55); 720 outb(vgaCRReg, tmp); 721} 722 723 724 725static Bool S3TiUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) 726{ 727 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 728 S3Ptr pS3 = S3PTR(pScrn); 729 return (pS3->hwCursor); 730} 731 732 733 734Bool S3Ti_CursorInit(ScreenPtr pScreen) 735{ 736 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 737 S3Ptr pS3 = S3PTR(pScrn); 738 xf86CursorInfoPtr pCurs; 739 740 if (!(pCurs = pS3->pCurs = xf86CreateCursorInfoRec())) 741 return FALSE; 742 743 pCurs->MaxWidth = 64; 744 pCurs->MaxHeight = 64; 745 pCurs->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | 746 HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 | 747 HARDWARE_CURSOR_NIBBLE_SWAPPED | 748 HARDWARE_CURSOR_BIT_ORDER_MSBFIRST; 749 750 pCurs->SetCursorColors = S3TiSetCursorColors; 751 pCurs->SetCursorPosition = S3TiSetCursorPosition; 752 pCurs->LoadCursorImage = S3TiLoadCursorImage; 753 pCurs->HideCursor = S3TiHideCursor; 754 pCurs->ShowCursor = S3TiShowCursor; 755 pCurs->UseHWCursor = S3TiUseHWCursor; 756 757 return xf86InitCursor(pScreen, pCurs); 758} 759