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