s3_IBMRGB.c revision b27e1915
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 "IBM.h" 38 39#include "s3.h" 40 41 42#define IBMRGB_WRITE_ADDR 0x3C8 /* CR55 low bit == 0 */ 43#define IBMRGB_RAMDAC_DATA 0x3C9 /* CR55 low bit == 0 */ 44#define IBMRGB_PIXEL_MASK 0x3C6 /* CR55 low bit == 0 */ 45#define IBMRGB_READ_ADDR 0x3C7 /* CR55 low bit == 0 */ 46#define IBMRGB_INDEX_LOW 0x3C8 /* CR55 low bit == 1 */ 47#define IBMRGB_INDEX_HIGH 0x3C9 /* CR55 low bit == 1 */ 48#define IBMRGB_INDEX_DATA 0x3C6 /* CR55 low bit == 1 */ 49#define IBMRGB_INDEX_CONTROL 0x3C7 /* CR55 low bit == 1 */ 50 51 52static void S3OutIBMRGBIndReg(ScrnInfoPtr pScrn, CARD32 reg, 53 unsigned char mask, unsigned char data) 54{ 55 S3Ptr pS3 = S3PTR(pScrn); 56 unsigned char tmp, tmp2 = 0x00; 57 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 58 59 outb(vgaCRIndex, 0x55); 60 tmp = inb(vgaCRReg) & 0xfc; 61 outb(vgaCRReg, tmp | 0x01); 62 63 outb(IBMRGB_INDEX_LOW, reg); 64 65 if (mask != 0x00) 66 tmp2 = inb(IBMRGB_INDEX_DATA) & mask; 67 outb(IBMRGB_INDEX_DATA, tmp2 | data); 68 69 outb(vgaCRIndex, 0x55); 70 outb(vgaCRReg, tmp); 71} 72 73 74static unsigned char S3InIBMRGBIndReg(ScrnInfoPtr pScrn, CARD32 reg) 75{ 76 S3Ptr pS3 = S3PTR(pScrn); 77 unsigned char tmp, ret; 78 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 79 80 outb(vgaCRIndex, 0x55); 81 tmp = inb(vgaCRReg) & 0xfc; 82 outb(vgaCRReg, tmp | 0x01); 83 84 outb(IBMRGB_INDEX_LOW, reg); 85 ret = inb(IBMRGB_INDEX_DATA); 86 87 outb(vgaCRIndex, 0x55); 88 outb(vgaCRReg, tmp); 89 90 return ret; 91} 92 93 94static void S3IBMWriteAddress(ScrnInfoPtr pScrn, CARD32 index) 95{ 96 outb(IBMRGB_WRITE_ADDR, index); 97} 98 99static void S3IBMWriteData(ScrnInfoPtr pScrn, unsigned char data) 100{ 101 outb(IBMRGB_INDEX_DATA, data); 102} 103 104static void S3IBMReadAddress(ScrnInfoPtr pScrn, CARD32 index) 105{ 106 outb(IBMRGB_READ_ADDR, index); 107} 108 109static unsigned char S3IBMReadData(ScrnInfoPtr pScrn) 110{ 111 return inb(IBMRGB_RAMDAC_DATA); 112} 113 114 115Bool S3ProbeIBMramdac(ScrnInfoPtr pScrn) 116{ 117 S3Ptr pS3 = S3PTR(pScrn); 118 119 if (pS3->Chipset != PCI_CHIP_968) 120 return FALSE; 121 122 pS3->RamDacRec = RamDacCreateInfoRec(); 123 pS3->RamDacRec->ReadDAC = S3InIBMRGBIndReg; 124 pS3->RamDacRec->WriteDAC = S3OutIBMRGBIndReg; 125 pS3->RamDacRec->ReadAddress = S3IBMReadAddress; 126 pS3->RamDacRec->WriteAddress = S3IBMWriteAddress; 127 pS3->RamDacRec->ReadData = S3IBMReadData; 128 pS3->RamDacRec->WriteData = S3IBMWriteData; 129 pS3->RamDacRec->LoadPalette = NULL; 130 131 if (!RamDacInit(pScrn, pS3->RamDacRec)) { 132 RamDacDestroyInfoRec(pS3->RamDacRec); 133 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RamDacInit failed\n"); 134 return FALSE; 135 } 136 137 pS3->RamDac = IBMramdacProbe(pScrn, S3IBMRamdacs); 138 if (pS3->RamDac) 139 return TRUE; 140 141 return FALSE; 142} 143 144static void S3ProgramIBMRGBClock(ScrnInfoPtr pScrn, int clk, unsigned char m, 145 unsigned char n, unsigned char df) 146{ 147 S3OutIBMRGBIndReg(pScrn, IBMRGB_misc_clock, ~1, 1); 148 149 S3OutIBMRGBIndReg(pScrn, IBMRGB_m0+2*clk, 0, (df<<6)|(m&0x3f)); 150 S3OutIBMRGBIndReg(pScrn, IBMRGB_n0+2*clk, 0, n); 151 152 S3OutIBMRGBIndReg(pScrn, IBMRGB_pll_ctrl2, 0xf0, clk); 153 S3OutIBMRGBIndReg(pScrn, IBMRGB_pll_ctrl1, 0xf8, 3); 154} 155 156 157static void S3IBMRGBSetClock(ScrnInfoPtr pScrn, long freq, int clk, long dacspeed, 158 long fref) 159{ 160 volatile double ffreq, fdacspeed, ffref; 161 volatile int df, n, m, max_n, min_df; 162 volatile int best_m=69, best_n=17, best_df=0; 163 volatile double diff, mindiff; 164 165#define FREQ_MIN 16250 166#define FREQ_MAX dacspeed 167 168 if (freq < FREQ_MIN) 169 ffreq = FREQ_MIN / 1000.0; 170 else if (freq > FREQ_MAX) 171 ffreq = FREQ_MAX / 1000.0; 172 else 173 ffreq = freq / 1000.0; 174 175 fdacspeed = dacspeed / 1e3; 176 ffref = fref / 1e3; 177 178 ffreq /= ffref; 179 ffreq *= 16; 180 mindiff = ffreq; 181 182 if (freq <= dacspeed/4) 183 min_df = 0; 184 else if (freq <= dacspeed/2) 185 min_df = 1; 186 else 187 min_df = 2; 188 189 for (df=0; df<4; df++) { 190 ffreq /= 2; 191 mindiff /= 2; 192 if (df < min_df) 193 continue; 194 195 if (df < 3) 196 max_n = fref / 1000 / 2; 197 else 198 max_n = fref / 1000; 199 if (max_n > 31) 200 max_n = 31; 201 202 for (n=2; n <= max_n; n++) { 203 m = (int)(ffreq * n + 0.5) - 65; 204 if (m < 0) 205 m = 0; 206 else if (m > 63) 207 m = 63; 208 diff = (m+65.0)/n-ffreq; 209 if (diff < 0) 210 diff = -diff; 211 if (diff < mindiff) { 212 mindiff = diff; 213 best_n = n; 214 best_m = m; 215 best_df = df; 216 } 217 } 218 } 219 220 S3ProgramIBMRGBClock(pScrn, clk, best_m, best_n, best_df); 221} 222 223void S3IBMRGB_Restore(ScrnInfoPtr pScrn) 224{ 225 S3Ptr pS3 = S3PTR(pScrn); 226 S3RegPtr restore = &pS3->SavedRegs; 227 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 228 int i; 229 230 for(i=0; i<0x100; i++) 231 S3OutIBMRGBIndReg(pScrn, i, 0, restore->dacregs[i]); 232 233 outb(vgaCRIndex, 0x22); 234 outb(vgaCRReg, restore->dacregs[0x100]); 235} 236 237 238void S3IBMRGB_Save(ScrnInfoPtr pScrn) 239{ 240 S3Ptr pS3 = S3PTR(pScrn); 241 S3RegPtr save = &pS3->SavedRegs; 242 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 243 int i; 244 245 for (i=0; i<0x100; i++) 246 save->dacregs[i] = S3InIBMRGBIndReg(pScrn, i); 247 248 outb(vgaCRIndex, 0x22); 249 save->dacregs[0x100] = inb(vgaCRReg); 250} 251 252 253void S3IBMRGB_PreInit(ScrnInfoPtr pScrn) 254{ 255 S3Ptr pS3 = S3PTR(pScrn); 256 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 257 unsigned char cr55, tmp; 258 259 outb(vgaCRIndex, 0x43); 260 tmp = inb(vgaCRReg); 261 outb(vgaCRReg, tmp & ~0x02); 262 263 outb(vgaCRIndex, 0x55); 264 cr55 = inb(vgaCRReg); 265 outb(vgaCRReg, (cr55 & ~0x03) | 0x01); /* set rs2 */ 266 267 tmp = inb(IBMRGB_INDEX_CONTROL); 268 outb(IBMRGB_INDEX_CONTROL, tmp & ~1); 269 outb(IBMRGB_INDEX_HIGH, 0); 270 271 outb(vgaCRIndex, 0x55); 272 outb(vgaCRReg, cr55 & ~0x03); 273 274 { 275 int m, n, df, mclk=0; 276 277 m = S3InIBMRGBIndReg(pScrn, IBMRGB_sysclk_vco_div); 278 n = S3InIBMRGBIndReg(pScrn, IBMRGB_sysclk_ref_div) & 0x1f; 279 df = m >> 6; 280 m &= 0x3f; 281 if (!n) { 282 m = 0; 283 n = 1; 284 } 285 mclk = ((pS3->RefClock*100 * (m+65)) / n / (8 >> df) + 50) / 100; 286 pS3->mclk = mclk; 287 xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "MCLK %1.3f MHz\n", 288 mclk / 1000.0); 289 } 290} 291 292 293void S3IBMRGB_Init(ScrnInfoPtr pScrn, DisplayModePtr mode) 294{ 295 S3Ptr pS3 = S3PTR(pScrn); 296 unsigned char tmp, blank; 297 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 298 299 S3IBMRGBSetClock(pScrn, mode->Clock, 2, pS3->MaxClock, 300 pS3->RefClock); 301 302 outb(0x3c4, 1); 303 blank = inb(0x3c5); 304 outb(0x3c5, blank | 0x20); 305 306 S3OutIBMRGBIndReg(pScrn, IBMRGB_misc_clock, 0xf0, 0x03); 307 S3OutIBMRGBIndReg(pScrn, IBMRGB_sync, 0, 0); 308 S3OutIBMRGBIndReg(pScrn, IBMRGB_hsync_pos, 0, 0); 309 S3OutIBMRGBIndReg(pScrn, IBMRGB_pwr_mgmt, 0, 0); 310 S3OutIBMRGBIndReg(pScrn, IBMRGB_dac_op, ~8, 0); 311 S3OutIBMRGBIndReg(pScrn, IBMRGB_dac_op, ~2, 2); 312 S3OutIBMRGBIndReg(pScrn, IBMRGB_pal_ctrl, 0, 0); 313 S3OutIBMRGBIndReg(pScrn, IBMRGB_misc1, ~0x43, 1); 314 S3OutIBMRGBIndReg(pScrn, IBMRGB_misc2, 0, 0x47); 315 316 outb(vgaCRIndex, 0x22); 317 tmp = inb(vgaCRReg); 318 if (pS3->s3Bpp == 1) 319 outb(vgaCRReg, tmp | 8); 320 else 321 outb(vgaCRReg, tmp & ~8); 322 323 outb(vgaCRIndex, 0x65); 324 outb(vgaCRReg, 0x00); /* ! 528 */ 325 326 outb(vgaCRIndex, 0x40); 327 outb(vgaCRReg, 0x11); 328 outb(vgaCRIndex, 0x55); 329 outb(vgaCRReg, 0x00); 330 331 switch (pScrn->depth) { 332 case 8: 333 S3OutIBMRGBIndReg(pScrn, IBMRGB_pix_fmt, 0xf8, 3); 334 S3OutIBMRGBIndReg(pScrn, IBMRGB_8bpp, 0, 0); 335 break; 336 case 15: 337 S3OutIBMRGBIndReg(pScrn, IBMRGB_pix_fmt, 0xf8, 4); 338 S3OutIBMRGBIndReg(pScrn, IBMRGB_16bpp, 0, 0xc0); 339 break; 340 case 16: 341 S3OutIBMRGBIndReg(pScrn, IBMRGB_pix_fmt, 0xf8, 4); 342 S3OutIBMRGBIndReg(pScrn, IBMRGB_16bpp, 0, 0xc2); 343 break; 344 } 345 346 outb(vgaCRIndex, 0x66); 347 tmp = inb(vgaCRReg) & 0xf8; 348 outb(vgaCRReg, tmp); 349 350 outb(vgaCRIndex, 0x58); 351 tmp = (inb(vgaCRReg) & 0xbf) | 0x40; 352 outb(vgaCRReg, tmp); 353 354 outb(vgaCRIndex, 0x67); 355 outb(vgaCRReg, 0x11); 356 357 switch (pScrn->bitsPerPixel) { 358 case 8: 359 tmp = 0x21; 360 break; 361 case 16: 362 tmp = 0x10; 363 break; 364 } 365 outb(vgaCRIndex, 0x6d); 366 outb(vgaCRReg, tmp); 367 368 outb(0x3c4, 1); 369 outb(0x3c5, blank); 370} 371 372 373/* hardware cursor */ 374 375static void S3IBMRGBSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) 376{ 377 S3Ptr pS3 = S3PTR(pScrn); 378 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 379 unsigned char tmp; 380 381 /* unlock sys regs */ 382 outb(vgaCRIndex, 0x39); 383 outb(vgaCRReg, 0xa5); 384 385 outb(vgaCRIndex, 0x55); 386 tmp = inb(vgaCRReg) & 0xfc; 387 outb(vgaCRReg, tmp | 0x01); 388 389 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col1_r); 390 outb(IBMRGB_INDEX_DATA, (bg & 0x00ff0000) >> 16); 391 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col1_g); 392 outb(IBMRGB_INDEX_DATA, (bg & 0x0000ff00) >> 8); 393 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col1_b); 394 outb(IBMRGB_INDEX_DATA, (bg & 0x000000ff)); 395 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col2_r); 396 outb(IBMRGB_INDEX_DATA, (fg & 0x00ff0000) >> 16); 397 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col2_g); 398 outb(IBMRGB_INDEX_DATA, (fg & 0x0000ff00) >> 8); 399 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col2_b); 400 outb(IBMRGB_INDEX_DATA, (fg & 0x000000ff)); 401 402 outb(vgaCRReg, tmp); 403} 404 405 406static void S3IBMRGBSetCursorPosition(ScrnInfoPtr pScrn, int x, int y) 407{ 408 S3Ptr pS3 = S3PTR(pScrn); 409 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 410 unsigned char tmp; 411 412 /* unlock sys regs */ 413 outb(vgaCRIndex, 0x39); 414 outb(vgaCRReg, 0xa5); 415 416 outb(vgaCRIndex, 0x55); 417 tmp = inb(vgaCRReg) & 0xfc; 418 outb(vgaCRReg, tmp | 0x01); 419 420 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_xl); 421 outb(IBMRGB_INDEX_DATA, x); 422 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_xh); 423 outb(IBMRGB_INDEX_DATA, x >> 8); 424 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_yl); 425 outb(IBMRGB_INDEX_DATA, y); 426 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_yh); 427 outb(IBMRGB_INDEX_DATA, y >> 8); 428 429 outb(vgaCRReg, tmp); 430} 431 432 433static void S3IBMRGBHideCursor(ScrnInfoPtr pScrn) 434{ 435 S3Ptr pS3 = S3PTR(pScrn); 436 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 437 438 /* unlock sys regs */ 439 outb(vgaCRIndex, 0x39); 440 outb(vgaCRReg, 0xa5); 441 442 S3OutIBMRGBIndReg(pScrn, IBMRGB_curs, ~3, 0x00); 443} 444 445 446static void S3IBMRGBShowCursor(ScrnInfoPtr pScrn) 447{ 448 S3Ptr pS3 = S3PTR(pScrn); 449 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 450 unsigned char tmp; 451 452 /* unlock sys regs */ 453 outb(vgaCRIndex, 0x39); 454 outb(vgaCRReg, 0xa5); 455 456 outb(vgaCRIndex, 0x55); 457 tmp = (inb(vgaCRReg) & 0xdf) | 0x20; 458 outb(vgaCRReg, tmp); 459 460 outb(vgaCRIndex, 0x45); 461 tmp = inb(vgaCRReg) & ~0x20; 462 outb(vgaCRReg, tmp); 463 464 S3OutIBMRGBIndReg(pScrn, IBMRGB_curs, 0, 0x27); 465} 466 467 468static void S3IBMRGBLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image) 469{ 470 S3Ptr pS3 = S3PTR(pScrn); 471 int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 472 unsigned char tmp, tmp2; 473 register int i; 474 475 /* unlock sys regs */ 476 outb(vgaCRIndex, 0x39); 477 outb(vgaCRReg, 0xa5); 478 479 outb(vgaCRIndex, 0x55); 480 tmp = inb(vgaCRReg) & 0xfc; 481 outb(vgaCRReg, tmp | 0x01); 482 483 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_hot_x); 484 outb(IBMRGB_INDEX_DATA, 0); 485 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_hot_y); 486 outb(IBMRGB_INDEX_DATA, 0); 487 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_xl); 488 outb(IBMRGB_INDEX_DATA, 0xff); 489 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_xh); 490 outb(IBMRGB_INDEX_DATA, 0x7f); 491 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_yl); 492 outb(IBMRGB_INDEX_DATA, 0xff); 493 outb(IBMRGB_INDEX_LOW, IBMRGB_curs_yh); 494 outb(IBMRGB_INDEX_DATA, 0x7f); 495 496 tmp2 = inb(IBMRGB_INDEX_CONTROL) & 0xfe; 497 outb(IBMRGB_INDEX_CONTROL, tmp2 | 1); /* enable auto increment */ 498 499 outb(IBMRGB_INDEX_HIGH, (unsigned char) (IBMRGB_curs_array >> 8)); 500 outb(IBMRGB_INDEX_LOW, (unsigned char) (IBMRGB_curs_array)); 501 502 for (i=0; i<1024; i++) 503 outb(IBMRGB_INDEX_DATA, *image++); 504 505 outb(IBMRGB_INDEX_HIGH, 0); 506 outb(IBMRGB_INDEX_CONTROL, tmp2); /* disable auto increment */ 507 outb(vgaCRIndex, 0x55); 508 outb(vgaCRReg, tmp); 509} 510 511 512static Bool S3IBMRGBUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) 513{ 514 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 515 S3Ptr pS3 = S3PTR(pScrn); 516 return (pS3->hwCursor); 517} 518 519 520Bool S3IBMRGB_CursorInit(ScreenPtr pScreen) 521{ 522 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 523 S3Ptr pS3 = S3PTR(pScrn); 524 xf86CursorInfoPtr pCurs; 525 526 if (!(pCurs = pS3->pCurs = xf86CreateCursorInfoRec())) 527 return FALSE; 528 529 pCurs->MaxWidth = 64; 530 pCurs->MaxHeight = 64; 531 pCurs->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | 532 HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 | 533 HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | 534 HARDWARE_CURSOR_NIBBLE_SWAPPED | 535 HARDWARE_CURSOR_BIT_ORDER_MSBFIRST; 536 537 pCurs->SetCursorColors = S3IBMRGBSetCursorColors; 538 pCurs->SetCursorPosition = S3IBMRGBSetCursorPosition; 539 pCurs->LoadCursorImage = S3IBMRGBLoadCursorImage; 540 pCurs->HideCursor = S3IBMRGBHideCursor; 541 pCurs->ShowCursor = S3IBMRGBShowCursor; 542 pCurs->UseHWCursor = S3IBMRGBUseHWCursor; 543 544 return xf86InitCursor(pScreen, pCurs); 545} 546 547 548