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