1/* 2Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved. 3Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. 4Copyright (C) 2008 Francisco Jerez. All Rights Reserved. 5 6Permission is hereby granted, free of charge, to any person obtaining a copy of 7this software and associated documentation files (the "Software"), to deal in 8the Software without restriction, including without limitation the rights to 9use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10of the Software, and to permit persons to whom the Software is furnished to do 11so, subject to the following conditions: 12 13The above copyright notice and this permission notice shall be included in all 14copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- 18NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 23Except as contained in this notice, the names of The XFree86 Project and 24Silicon Motion shall not be used in advertising or otherwise to promote the 25sale, use or other dealings in this Software without prior written 26authorization from The XFree86 Project or Silicon Motion. 27*/ 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#include "smi.h" 34#include "smi_crtc.h" 35#include "smilynx.h" 36 37static void 38SMILynx_CrtcVideoInit_crt(xf86CrtcPtr crtc) 39{ 40 ScrnInfoPtr pScrn=crtc->scrn; 41 SMIPtr pSmi = SMIPTR(pScrn); 42 int pitch; 43 44 ENTER(); 45 46 switch (pScrn->bitsPerPixel) { 47 case 8: 48 WRITE_VPR(pSmi, 0x00, 0x00000000); 49 break; 50 case 16: 51 WRITE_VPR(pSmi, 0x00, 0x00020000); 52 break; 53 case 24: 54 WRITE_VPR(pSmi, 0x00, 0x00040000); 55 break; 56 case 32: 57 WRITE_VPR(pSmi, 0x00, 0x00030000); 58 break; 59 } 60 61 pitch = (crtc->rotatedData? crtc->mode.HDisplay : pScrn->displayWidth) * pSmi->Bpp; 62 pitch = (pitch + 15) & ~15; 63 64 WRITE_VPR(pSmi, 0x10, (crtc->mode.HDisplay * pSmi->Bpp) >> 3 << 16 | pitch >> 3); 65 66 LEAVE(); 67} 68 69static void 70SMILynx_CrtcVideoInit_lcd(xf86CrtcPtr crtc) 71{ 72 ScrnInfoPtr pScrn=crtc->scrn; 73 SMIPtr pSmi = SMIPTR(pScrn); 74 SMIRegPtr mode = pSmi->mode; 75 CARD16 fifo_readoffset,fifo_writeoffset; 76 77 ENTER(); 78 79 /* Set display depth */ 80 if (pScrn->bitsPerPixel > 8) 81 mode->SR31 |= 0x40; /* 16 bpp */ 82 else 83 mode->SR31 &= ~0x40; /* 8 bpp */ 84 85 /* FIFO1/2 Read Offset*/ 86 fifo_readoffset = (crtc->rotatedData? crtc->mode.HDisplay : pScrn->displayWidth) * pSmi->Bpp; 87 fifo_readoffset = ((fifo_readoffset + 15) & ~15) >> 3; 88 89 /* FIFO1 Read Offset */ 90 mode->SR44 = fifo_readoffset & 0x000000FF; 91 /* FIFO2 Read Offset */ 92 mode->SR4B = fifo_readoffset & 0x000000FF; 93 94 if(pSmi->Chipset == SMI_LYNX3DM){ 95 /* FIFO1/2 Read Offset overflow */ 96 mode->SR4C = (((fifo_readoffset & 0x00000300) >> 8) << 2) | 97 (((fifo_readoffset & 0x00000300) >> 8) << 6); 98 }else{ 99 /* FIFO1 Read Offset overflow */ 100 mode->SR45 = (mode->SR45 & 0x3F) | ((fifo_readoffset & 0x00000300) >> 8) << 6; 101 /* FIFO2 Read Offset overflow */ 102 mode->SR4C = (((fifo_readoffset & 0x00000300) >> 8) << 6); 103 } 104 105 /* FIFO Write Offset */ 106 fifo_writeoffset = crtc->mode.HDisplay * pSmi->Bpp >> 3; 107 mode->SR48 = fifo_writeoffset & 0x000000FF; 108 mode->SR49 = (fifo_writeoffset & 0x00000300) >> 8; 109 110 /* set FIFO levels */ 111 mode->SR4A = 0x41; 112 113 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, mode->SR31); 114 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x44, mode->SR44); 115 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x45, mode->SR45); 116 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x48, mode->SR48); 117 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x49, mode->SR49); 118 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4A, mode->SR4A); 119 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4B, mode->SR4B); 120 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4C, mode->SR4C); 121 122 LEAVE(); 123} 124 125static void 126SMI730_CrtcVideoInit(xf86CrtcPtr crtc) 127{ 128 ScrnInfoPtr pScrn=crtc->scrn; 129 SMIPtr pSmi = SMIPTR(pScrn); 130 int pitch; 131 132 ENTER(); 133 134 switch (pScrn->bitsPerPixel) { 135 case 8: 136 WRITE_VPR(pSmi, 0x00, 0x00000000); 137 WRITE_FPR(pSmi, FPR00, 0x00080000); 138 break; 139 case 16: 140 WRITE_VPR(pSmi, 0x00, 0x00020000); 141 WRITE_FPR(pSmi, FPR00, 0x000A0000); 142 break; 143 case 24: 144 WRITE_VPR(pSmi, 0x00, 0x00040000); 145 WRITE_FPR(pSmi, FPR00, 0x000C0000); 146 break; 147 case 32: 148 WRITE_VPR(pSmi, 0x00, 0x00030000); 149 WRITE_FPR(pSmi, FPR00, 0x000B0000); 150 break; 151 } 152 153 pitch = (crtc->rotatedData? crtc->mode.HDisplay : pScrn->displayWidth) * pSmi->Bpp; 154 pitch = (pitch + 15) & ~15; 155 156 WRITE_VPR(pSmi, 0x10, (crtc->mode.HDisplay * pSmi->Bpp) >> 3 << 16 | pitch >> 3); 157 WRITE_FPR(pSmi, FPR10, (crtc->mode.HDisplay * pSmi->Bpp) >> 3 << 16 | pitch >> 3); 158 159 LEAVE(); 160} 161 162static void 163SMILynx_CrtcAdjustFrame(xf86CrtcPtr crtc, int x, int y) 164{ 165 ScrnInfoPtr pScrn=crtc->scrn; 166 SMIPtr pSmi = SMIPTR(pScrn); 167 SMIRegPtr mode = pSmi->mode; 168 xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn); 169 CARD32 Base; 170 171 ENTER(); 172 173 if(crtc->rotatedData) 174 Base = (char*)crtc->rotatedData - (char*)pSmi->FBBase; 175 else 176 Base = pSmi->FBOffset + (x + y * pScrn->displayWidth) * pSmi->Bpp; 177 178 179 if (SMI_LYNX3D_SERIES(pSmi->Chipset) || 180 SMI_COUGAR_SERIES(pSmi->Chipset)) { 181 Base = (Base + 15) & ~15; 182 while ((Base % pSmi->Bpp) > 0) { 183 Base -= 16; 184 } 185 } else { 186 Base = (Base + 7) & ~7; 187 while ((Base % pSmi->Bpp) > 0) 188 Base -= 8; 189 } 190 191 Base >>= 3; 192 193 if(SMI_COUGAR_SERIES(pSmi->Chipset)){ 194 WRITE_VPR(pSmi, 0x0C, Base); 195 WRITE_FPR(pSmi, FPR0C, Base); 196 }else{ 197 if(pSmi->Dualhead && crtc == crtcConf->crtc[1]){ 198 /* LCD */ 199 200 /* FIFO1 read start address */ 201 mode->SR40 = Base & 0x000000FF; 202 mode->SR41 = (Base & 0x0000FF00) >> 8; 203 204 /* FIFO2 read start address */ 205 mode->SR42 = Base & 0x000000FF; 206 mode->SR43 = (Base & 0x0000FF00) >> 8; 207 208 /* FIFO1/2 read start address overflow */ 209 if(pSmi->Chipset == SMI_LYNX3DM) 210 mode->SR45 = (Base & 0x000F0000) >> 16 | (Base & 0x000F0000) >> 16 << 4; 211 else 212 mode->SR45 = (mode->SR45 & 0xC0) | 213 (Base & 0x00070000) >> 16 | (Base & 0x00070000) >> 16 << 3; 214 215 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x40, mode->SR40); 216 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x41, mode->SR41); 217 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x42, mode->SR42); 218 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x43, mode->SR43); 219 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x45, mode->SR45); 220 221 }else{ 222 /* CRT or single head */ 223 WRITE_VPR(pSmi, 0x0C, Base); 224 } 225 } 226 227 LEAVE(); 228} 229 230static Bool 231SMILynx_CrtcModeFixup(xf86CrtcPtr crtc, 232 DisplayModePtr mode, 233 DisplayModePtr adjusted_mode) 234{ 235 ScrnInfoPtr pScrn=crtc->scrn; 236 SMIPtr pSmi = SMIPTR(pScrn); 237 238 ENTER(); 239 240 if (pSmi->Chipset == SMI_LYNXEMplus) { 241 /* Adjust the pixel clock in case it is near one of the known 242 stable frequencies (KHz) */ 243 int stable_clocks[] = {46534,}; 244 int epsilon = 3000; 245 int i; 246 247 for (i=0; i < sizeof(stable_clocks)/sizeof(int); i++) { 248 if ( abs(mode->Clock - stable_clocks[i]) < epsilon) { 249 adjusted_mode->Clock = stable_clocks[i]; 250 break; 251 } 252 } 253 } 254 255 LEAVE(TRUE); 256} 257 258static void 259SMILynx_CrtcModeSet_vga(xf86CrtcPtr crtc, 260 DisplayModePtr mode, 261 DisplayModePtr adjusted_mode, 262 int x, int y) 263{ 264 ScrnInfoPtr pScrn=crtc->scrn; 265 SMIPtr pSmi = SMIPTR(pScrn); 266 SMIRegPtr reg = pSmi->mode; 267 vgaHWPtr hwp = VGAHWPTR(pScrn); 268 int vgaIOBase = hwp->IOBase; 269 int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET; 270 int vgaCRData = vgaIOBase + VGA_CRTC_DATA_OFFSET; 271 vgaRegPtr vganew = &hwp->ModeReg; 272 273 ENTER(); 274 275 /* Initialize Video Processor Registers */ 276 277 SMICRTC(crtc)->video_init(crtc); 278 SMILynx_CrtcAdjustFrame(crtc, x,y); 279 280 281 /* Program the PLL */ 282 283 /* calculate vclk1 */ 284 if (SMI_LYNX_SERIES(pSmi->Chipset)) { 285 SMI_CommonCalcClock(pScrn->scrnIndex, adjusted_mode->Clock, 286 1, 1, 63, 0, 3, 287 pSmi->clockRange.minClock, 288 pSmi->clockRange.maxClock, 289 ®->SR6C, ®->SR6D); 290 } else { 291 SMI_CommonCalcClock(pScrn->scrnIndex, adjusted_mode->Clock, 292 1, 1, 63, 0, 1, 293 pSmi->clockRange.minClock, 294 pSmi->clockRange.maxClock, 295 ®->SR6C, ®->SR6D); 296 } 297 298 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C, reg->SR6C); 299 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D, reg->SR6D); 300 301 302 /* Adjust mode timings */ 303 304 if (!vgaHWInit(pScrn, mode)) { 305 LEAVE(); 306 } 307 308 if ((mode->HDisplay == 640) && SMI_LYNXM_SERIES(pSmi->Chipset)) { 309 vganew->MiscOutReg &= ~0x0C; 310 } else { 311 vganew->MiscOutReg |= 0x0C; 312 } 313 vganew->MiscOutReg |= 0x20; 314 315 { 316 unsigned long HTotal=(mode->CrtcHTotal>>3)-5; 317 unsigned long HBlankEnd=(mode->CrtcHBlankEnd>>3)-1; 318 unsigned long VTotal=mode->CrtcVTotal-2; 319 unsigned long VDisplay=mode->CrtcVDisplay-1; 320 unsigned long VBlankStart=mode->CrtcVBlankStart-1; 321 unsigned long VBlankEnd=mode->CrtcVBlankEnd-1; 322 unsigned long VSyncStart=mode->CrtcVSyncStart; 323 324 /* Fix HBlankEnd/VBlankEnd */ 325 if((mode->CrtcHBlankEnd >> 3) == (mode->CrtcHTotal >> 3)) HBlankEnd=0; 326 if(mode->CrtcVBlankEnd == mode->CrtcVTotal) VBlankEnd=0; 327 328 vganew->CRTC[3] = (vganew->CRTC[3] & ~0x1F) | (HBlankEnd & 0x1F); 329 vganew->CRTC[5] = (vganew->CRTC[5] & ~0x80) | (HBlankEnd & 0x20) >> 5 << 7; 330 vganew->CRTC[22] = VBlankEnd & 0xFF; 331 332 /* Write the overflow from several VGA registers */ 333 reg->CR30 = (VTotal & 0x400) >> 10 << 3 | 334 (VDisplay & 0x400) >> 10 << 2 | 335 (VBlankStart & 0x400) >> 10 << 1 | 336 (VSyncStart & 0x400) >> 10 << 0; 337 338 if(pSmi->Chipset == SMI_LYNX3DM) 339 reg->CR30 |= (HTotal & 0x100) >> 8 << 6; 340 341 reg->CR33 = (HBlankEnd & 0xC0) >> 6 << 5 | (VBlankEnd & 0x300) >> 8 << 3; 342 } 343 344 vgaHWRestore(pScrn, vganew, VGA_SR_MODE); 345 346 VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x30, reg->CR30); 347 VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, reg->CR33); 348 349 LEAVE(); 350} 351 352static void 353SMILynx_CrtcModeSet_crt(xf86CrtcPtr crtc, 354 DisplayModePtr mode, 355 DisplayModePtr adjusted_mode, 356 int x, int y) 357{ 358 ScrnInfoPtr pScrn=crtc->scrn; 359 SMIPtr pSmi = SMIPTR(pScrn); 360 SMIRegPtr reg = pSmi->mode; 361 vgaHWPtr hwp = VGAHWPTR(pScrn); 362 int vgaIOBase = hwp->IOBase; 363 int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET; 364 int vgaCRData = vgaIOBase + VGA_CRTC_DATA_OFFSET; 365 int i; 366 367 ENTER(); 368 369 /* Initialize Video Processor Registers */ 370 371 SMILynx_CrtcVideoInit_crt(crtc); 372 SMILynx_CrtcAdjustFrame(crtc, x,y); 373 374 375 /* Program the PLL */ 376 377 /* calculate vclk1 */ 378 if (SMI_LYNX_SERIES(pSmi->Chipset)) { 379 SMI_CommonCalcClock(pScrn->scrnIndex, adjusted_mode->Clock, 380 1, 1, 63, 0, 3, 381 pSmi->clockRange.minClock, 382 pSmi->clockRange.maxClock, 383 ®->SR6C, ®->SR6D); 384 } else { 385 SMI_CommonCalcClock(pScrn->scrnIndex, adjusted_mode->Clock, 386 1, 1, 63, 0, 1, 387 pSmi->clockRange.minClock, 388 pSmi->clockRange.maxClock, 389 ®->SR6C, ®->SR6D); 390 } 391 392 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C, reg->SR6C); 393 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D, reg->SR6D); 394 395 396 /* Adjust mode timings */ 397 /* In virtual refresh mode, the CRT timings are controlled through 398 the shadow VGA registers */ 399 400 { 401 unsigned long HTotal=(mode->CrtcHTotal>>3)-5; 402 unsigned long HDisplay=(mode->CrtcHDisplay>>3)-1; 403 unsigned long HBlankStart=(mode->CrtcHBlankStart>>3)-1; 404 unsigned long HBlankEnd=(mode->CrtcHBlankEnd>>3)-1; 405 unsigned long HSyncStart=mode->CrtcHSyncStart>>3; 406 unsigned long HSyncEnd=mode->CrtcHSyncEnd>>3; 407 unsigned long VTotal=mode->CrtcVTotal-2; 408 unsigned long VDisplay=mode->CrtcVDisplay-1; 409 unsigned long VBlankStart=mode->CrtcVBlankStart-1; 410 unsigned long VBlankEnd=mode->CrtcVBlankEnd-1; 411 unsigned long VSyncStart=mode->CrtcVSyncStart; 412 unsigned long VSyncEnd=mode->CrtcVSyncEnd; 413 414 /* Fix HBlankEnd/VBlankEnd */ 415 if((mode->CrtcHBlankEnd >> 3) == (mode->CrtcHTotal >> 3)) HBlankEnd=0; 416 if(mode->CrtcVBlankEnd == mode->CrtcVTotal) VBlankEnd=0; 417 418 reg->CR40 [0x0] = HTotal & 0xFF; 419 reg->CR40 [0x1] = HBlankStart & 0xFF; 420 reg->CR40 [0x2] = HBlankEnd & 0x1F; 421 reg->CR40 [0x3] = HSyncStart & 0xFF; 422 reg->CR40 [0x4] = (HBlankEnd & 0x20) >> 5 << 7 | 423 (HSyncEnd & 0x1F); 424 reg->CR40 [0x5] = VTotal & 0xFF; 425 reg->CR40 [0x6] = VBlankStart & 0xFF; 426 reg->CR40 [0x7] = VBlankEnd & 0xFF; 427 reg->CR40 [0x8] = VSyncStart & 0xFF; 428 reg->CR40 [0x9] = VSyncEnd & 0x0F; 429 reg->CR40 [0xA] = (VSyncStart & 0x200) >> 9 << 7 | 430 (VDisplay & 0x200) >> 9 << 6 | 431 (VTotal & 0x200) >> 9 << 5 | 432 (VBlankStart & 0x100) >> 8 << 3 | 433 (VSyncStart & 0x100) >> 8 << 2 | 434 (VDisplay & 0x100) >> 8 << 1 | 435 (VTotal & 0x100) >> 8 << 0; 436 reg->CR40 [0xB] = ((mode->Flags & V_NVSYNC)?1:0) << 7 | 437 ((mode->Flags & V_NHSYNC)?1:0) << 6 | 438 (VBlankStart & 0x200) >> 9 << 5; 439 reg->CR40 [0xC] = HDisplay & 0xFF; 440 reg->CR40 [0xD] = VDisplay & 0xFF; 441 442 reg->CR30 = (VTotal & 0x400) >> 10 << 3 | 443 (VDisplay & 0x400) >> 10 << 2 | 444 (VBlankStart & 0x400) >> 10 << 1 | 445 (VSyncStart & 0x400) >> 10 << 0; 446 447 if(pSmi->Chipset == SMI_LYNX3DM) 448 reg->CR30 |= (HTotal & 0x100) >> 8 << 6; 449 450 reg->CR33 = (HBlankEnd & 0xC0) >> 6 << 5 | (VBlankEnd & 0x300) >> 8 << 3; 451 452 } 453 454 /* Select primary set of shadow registers */ 455 VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, reg->CR90[0xE] & ~0x20); 456 457 for(i=0; i <= 0xD; i++) 458 VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i, reg->CR40[i]); 459 460 VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x30, reg->CR30); 461 VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, reg->CR33); 462 463 LEAVE(); 464} 465 466static void 467SMILynx_CrtcModeSet_lcd(xf86CrtcPtr crtc, 468 DisplayModePtr mode, 469 DisplayModePtr adjusted_mode, 470 int x, int y) 471{ 472 ScrnInfoPtr pScrn=crtc->scrn; 473 SMIPtr pSmi = SMIPTR(pScrn); 474 SMIRegPtr reg = pSmi->mode; 475 476 ENTER(); 477 478 /* Initialize the flat panel video processor */ 479 480 SMILynx_CrtcVideoInit_lcd(crtc); 481 SMILynx_CrtcAdjustFrame(crtc,x,y); 482 483 484 /* Program the PLL */ 485 486 /* calculate vclk2 */ 487 if (SMI_LYNX_SERIES(pSmi->Chipset)) { 488 SMI_CommonCalcClock(pScrn->scrnIndex, adjusted_mode->Clock, 489 1, 1, 63, 0, 0, 490 pSmi->clockRange.minClock, 491 pSmi->clockRange.maxClock, 492 ®->SR6E, ®->SR6F); 493 } else { 494 SMI_CommonCalcClock(pScrn->scrnIndex, adjusted_mode->Clock, 495 1, 1, 63, 0, 1, 496 pSmi->clockRange.minClock, 497 pSmi->clockRange.maxClock, 498 ®->SR6E, ®->SR6F); 499 } 500 501 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6E, reg->SR6E); 502 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6F, reg->SR6F); 503 504 505 /* Adjust mode timings */ 506 { 507 unsigned long HTotal=(mode->CrtcHTotal>>3)-1; 508 unsigned long HDisplay=(mode->CrtcHDisplay>>3)-1; 509 unsigned long HSyncStart=(mode->CrtcHSyncStart>>3); 510 unsigned long HSyncWidth=((mode->CrtcHSyncEnd - mode->CrtcHSyncStart) >> 3) - 1; 511 unsigned long VTotal=mode->CrtcVTotal-1; 512 unsigned long VDisplay=mode->CrtcVDisplay-1; 513 unsigned long VSyncStart=mode->CrtcVSyncStart-1; 514 unsigned long VSyncWidth=mode->CrtcVSyncEnd - mode->CrtcVSyncStart - 1; 515 516 reg->SR50 = (VTotal & 0x700) >> 8 << 1 | 517 (HSyncStart & 0x100) >> 8 << 0; 518 reg->SR51 = (VSyncStart & 0x700) >> 8 << 5 | 519 (VDisplay & 0x700) >> 8 << 2 | 520 (HDisplay & 0x100) >> 8 << 1 | 521 (HTotal & 0x100) >> 8 << 0; 522 reg->SR52 = HTotal & 0xFF; 523 reg->SR53 = HDisplay & 0xFF; 524 reg->SR54 = HSyncStart & 0xFF; 525 reg->SR55 = VTotal & 0xFF; 526 reg->SR56 = VDisplay & 0xFF; 527 reg->SR57 = VSyncStart & 0xFF; 528 reg->SR5A = (HSyncWidth & 0x1F) << 3 | 529 (VSyncWidth & 0x07) << 0; 530 531 /* XXX - Why is the polarity hardcoded here? */ 532 reg->SR32 &= ~0x18; 533 if (mode->HDisplay == 800) { 534 reg->SR32 |= 0x18; 535 } 536 if ((mode->HDisplay == 1024) && SMI_LYNXM_SERIES(pSmi->Chipset)) { 537 reg->SR32 |= 0x18; 538 } 539 } 540 541 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32, reg->SR32); 542 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x50, reg->SR50); 543 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x51, reg->SR51); 544 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x52, reg->SR52); 545 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x53, reg->SR53); 546 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x54, reg->SR54); 547 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x55, reg->SR55); 548 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x56, reg->SR56); 549 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x57, reg->SR57); 550 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x5A, reg->SR5A); 551 552 LEAVE(); 553} 554 555static void 556SMILynx_CrtcModeSet_bios(xf86CrtcPtr crtc, 557 DisplayModePtr mode, 558 DisplayModePtr adjusted_mode, 559 int x, int y) 560{ 561 ScrnInfoPtr pScrn=crtc->scrn; 562 SMIPtr pSmi = SMIPTR(pScrn); 563 SMIRegPtr reg = pSmi->mode; 564 int i; 565 CARD8 tmp; 566 567 ENTER(); 568#ifdef USE_INT10 569 /* Find the INT 10 mode number */ 570 { 571 static struct { 572 int x, y, bpp; 573 CARD16 mode; 574 } modeTable[] = 575 { 576 { 640, 480, 8, 0x50 }, 577 { 640, 480, 16, 0x52 }, 578 { 640, 480, 24, 0x53 }, 579 { 640, 480, 32, 0x54 }, 580 { 800, 480, 8, 0x4A }, 581 { 800, 480, 16, 0x4C }, 582 { 800, 480, 24, 0x4D }, 583 { 800, 600, 8, 0x55 }, 584 { 800, 600, 16, 0x57 }, 585 { 800, 600, 24, 0x58 }, 586 { 800, 600, 32, 0x59 }, 587 { 1024, 768, 8, 0x60 }, 588 { 1024, 768, 16, 0x62 }, 589 { 1024, 768, 24, 0x63 }, 590 { 1024, 768, 32, 0x64 }, 591 { 1280, 1024, 8, 0x65 }, 592 { 1280, 1024, 16, 0x67 }, 593 { 1280, 1024, 24, 0x68 }, 594 { 1280, 1024, 32, 0x69 }, 595 }; 596 597 reg->mode = 0; 598 for (i = 0; i < sizeof(modeTable) / sizeof(modeTable[0]); i++) { 599 if ((modeTable[i].x == mode->HDisplay) && 600 (modeTable[i].y == mode->VDisplay) && 601 (modeTable[i].bpp == pScrn->bitsPerPixel)) { 602 reg->mode = modeTable[i].mode; 603 break; 604 } 605 } 606 } 607#endif 608 if(!reg->mode){ 609 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SMILynx_CrtcModeSet_bios: Not a known BIOS mode: " 610 "falling back to direct modesetting.\n"); 611 SMILynx_CrtcModeSet_vga(crtc,mode,adjusted_mode,x,y); 612 LEAVE(); 613 } 614#ifdef USE_INT10 615 pSmi->pInt10->num = 0x10; 616 pSmi->pInt10->ax = reg->mode | 0x80; 617 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode 0x%02X\n", 618 reg->mode); 619 xf86ExecX86int10(pSmi->pInt10); 620 621 /* Enable linear mode. */ 622 outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18); 623 tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA); 624 outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp | 0x01); 625 626 /* Enable DPR/VPR registers. */ 627 tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21); 628 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03); 629 630 631 /* Initialize Video Processor Registers */ 632 633 SMICRTC(crtc)->video_init(crtc); 634 SMILynx_CrtcAdjustFrame(crtc, x,y); 635#endif 636 LEAVE(); 637} 638 639static void 640SMILynx_CrtcLoadLUT_crt(xf86CrtcPtr crtc) 641{ 642 ScrnInfoPtr pScrn = crtc->scrn; 643 SMIPtr pSmi = SMIPTR(pScrn); 644 SMIRegPtr mode = pSmi->mode; 645 SMICrtcPrivatePtr crtcPriv = SMICRTC(crtc); 646 int i; 647 648 ENTER(); 649 650 /* Write CRT RAM only */ 651 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX,VGA_SEQ_DATA,0x66,(mode->SR66 & ~0x30) | 0x20); 652 653 for(i=0;i<256;i++){ 654 VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, i); 655 VGAOUT8(pSmi, VGA_DAC_DATA, crtcPriv->lut_r[i] >> 8); 656 VGAOUT8(pSmi, VGA_DAC_DATA, crtcPriv->lut_g[i] >> 8); 657 VGAOUT8(pSmi, VGA_DAC_DATA, crtcPriv->lut_b[i] >> 8); 658 } 659 660 LEAVE(); 661} 662 663static void 664SMILynx_CrtcLoadLUT_lcd(xf86CrtcPtr crtc) 665{ 666 ENTER(); 667 668 /* XXX - Is it possible to load LCD LUT in Virtual Refresh mode? */ 669 670 LEAVE(); 671} 672 673static void 674SMILynx_CrtcSetCursorColors_crt (xf86CrtcPtr crtc, int bg, int fg) 675{ 676 ScrnInfoPtr pScrn = crtc->scrn; 677 SMIPtr pSmi = SMIPTR(pScrn); 678 CARD8 packedFG,packedBG; 679 680 ENTER(); 681 682 /* Pack the true color into 8 bit */ 683 packedFG = (fg & 0xE00000) >> 16 | 684 (fg & 0x00E000) >> 11 | 685 (fg & 0x0000C0) >> 6; 686 packedBG = (bg & 0xE00000) >> 16 | 687 (bg & 0x00E000) >> 11 | 688 (bg & 0x0000C0) >> 6; 689 690 /* Program the colors */ 691 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8C, packedFG); 692 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8D, packedBG); 693 694 /* Program FPR copy when on the 730 */ 695 if (pSmi->Chipset == SMI_COUGAR3DR) { 696 CARD32 fpr15c; 697 698 fpr15c = READ_FPR(pSmi, FPR15C) & FPR15C_MASK_HWCADDREN; 699 fpr15c |= packedFG; 700 fpr15c |= packedBG << 8; 701 WRITE_FPR(pSmi, FPR15C, fpr15c); 702 } 703 704 LEAVE(); 705} 706 707static void 708SMILynx_CrtcSetCursorPosition_crt (xf86CrtcPtr crtc, int x, int y) 709{ 710 ScrnInfoPtr pScrn = crtc->scrn; 711 SMIPtr pSmi = SMIPTR(pScrn); 712 713 ENTER(); 714 715 if (x >= 0) { 716 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x88, 717 x & 0xFF); 718 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x89, 719 (x >> 8) & 0x07); 720 } 721 else { 722 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x88, 723 (-x) & (SMILYNX_MAX_CURSOR - 1)); 724 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x89, 725 0x08); 726 } 727 728 if (y >= 0) { 729 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8A, 730 y & 0xFF); 731 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8B, 732 (y >> 8) & 0x07); 733 } 734 else { 735 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8A, 736 (-y) & (SMILYNX_MAX_CURSOR - 1)); 737 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 738 0x8B, 0x08); 739 } 740 741 /* Program FPR copy when on the 730 */ 742 if (pSmi->Chipset == SMI_COUGAR3DR) { 743 CARD32 fpr158; 744 745 if (x >= 0) 746 fpr158 = (x & FPR158_MASK_MAXBITS) << 16; 747 else 748 fpr158 = ((-x & FPR158_MASK_MAXBITS) | 749 FPR158_MASK_BOUNDARY) << 16; 750 751 if (y >= 0) 752 fpr158 |= y & FPR158_MASK_MAXBITS; 753 else 754 fpr158 |= (-y & FPR158_MASK_MAXBITS) | FPR158_MASK_BOUNDARY; 755 756 /* Program combined coordinates */ 757 WRITE_FPR(pSmi, FPR158, fpr158); 758 } 759 760 LEAVE(); 761} 762 763static void 764SMILynx_CrtcShowCursor_crt (xf86CrtcPtr crtc) 765{ 766 ScrnInfoPtr pScrn = crtc->scrn; 767 SMIPtr pSmi = SMIPTR(pScrn); 768 char tmp; 769 770 ENTER(); 771 772 /* Show cursor */ 773 tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81); 774 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, tmp | 0x80); 775 776 /* Program FPR copy when on the 730 */ 777 if (pSmi->Chipset == SMI_COUGAR3DR) { 778 CARD32 fpr15c; 779 780 /* turn on the top bit */ 781 fpr15c = READ_FPR(pSmi, FPR15C); 782 fpr15c |= FPR15C_MASK_HWCENABLE; 783 WRITE_FPR(pSmi, FPR15C, fpr15c); 784 } 785 786 LEAVE(); 787} 788 789static void 790SMILynx_CrtcHideCursor_crt (xf86CrtcPtr crtc) 791{ 792 ScrnInfoPtr pScrn = crtc->scrn; 793 SMIPtr pSmi = SMIPTR(pScrn); 794 char tmp; 795 796 ENTER(); 797 798 /* Hide cursor */ 799 tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81); 800 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, tmp & ~0x80); 801 802 /* Program FPR copy when on the 730 */ 803 if (pSmi->Chipset == SMI_COUGAR3DR) { 804 CARD32 fpr15c; 805 806 /* turn off the top bit */ 807 fpr15c = READ_FPR(pSmi, FPR15C); 808 fpr15c &= ~FPR15C_MASK_HWCENABLE; 809 WRITE_FPR(pSmi, FPR15C, fpr15c); 810 } 811 812 813 LEAVE(); 814} 815 816static void 817SMILynx_CrtcLoadCursorImage_crt (xf86CrtcPtr crtc, CARD8 *image) 818{ 819 ScrnInfoPtr pScrn = crtc->scrn; 820 SMIPtr pSmi = SMIPTR(pScrn); 821 CARD8 tmp; 822 int i; 823 CARD8* dst; 824 825 ENTER(); 826 827 /* Load storage location. */ 828 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x80, 829 pSmi->FBCursorOffset / 2048); 830 tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81) & 0x80; 831 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, 832 tmp | ((pSmi->FBCursorOffset / 2048) >> 8)); 833 834 /* Program FPR copy when on the 730 */ 835 if (pSmi->Chipset == SMI_COUGAR3DR) { 836 CARD32 fpr15c; 837 838 /* put address in upper word, and disable the cursor */ 839 fpr15c = READ_FPR(pSmi, FPR15C) & FPR15C_MASK_HWCCOLORS; 840 fpr15c |= (pSmi->FBCursorOffset / 2048) << 16; 841 WRITE_FPR(pSmi, FPR15C, fpr15c); 842 } 843 844 /* Copy cursor image to framebuffer storage */ 845 dst = pSmi->FBBase + pSmi->FBCursorOffset; 846 for(i=0; i < (SMILYNX_MAX_CURSOR * SMILYNX_MAX_CURSOR >> 2); i++){ 847 *(dst++) = image[i]; 848 if((i & 0x3) == 0x3) dst+=4; 849 } 850 851 LEAVE(); 852} 853 854static void 855SMILynx_CrtcDPMS_crt(xf86CrtcPtr crtc, int mode) 856{ 857 ScrnInfoPtr pScrn = crtc->scrn; 858 SMIPtr pSmi = SMIPTR(pScrn); 859 SMIRegPtr reg = pSmi->mode; 860 vgaHWPtr hwp = VGAHWPTR(pScrn); 861 862 ENTER(); 863 864 if(mode == DPMSModeOff) 865 reg->SR21 |= 0x88; /* Disable DAC and color palette RAM */ 866 else 867 reg->SR21 &= ~0x88; /* Enable DAC and color palette RAM */ 868 869 /* Wait for vertical retrace */ 870 while (hwp->readST01(hwp) & 0x8) ; 871 while (!(hwp->readST01(hwp) & 0x8)) ; 872 873 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, reg->SR21); 874 875 if(mode == DPMSModeOn){ 876 /* Reload the LUT */ 877 SMILynx_CrtcLoadLUT_crt(crtc); 878 } 879 880 LEAVE(); 881} 882 883static void 884SMILynx_CrtcDPMS_lcd(xf86CrtcPtr crtc, int mode) 885{ 886 ScrnInfoPtr pScrn = crtc->scrn; 887 SMIPtr pSmi = SMIPTR(pScrn); 888 SMIRegPtr reg = pSmi->mode; 889 vgaHWPtr hwp = VGAHWPTR(pScrn); 890 891 ENTER(); 892 893 if(mode == DPMSModeOff) 894 reg->SR31 &= ~0x80; /* Disable Virtual Refresh */ 895 else 896 reg->SR31 |= 0x80; /* Enable Virtual Refresh */ 897 898 /* Wait for vertical retrace */ 899 while (hwp->readST01(hwp) & 0x8) ; 900 while (!(hwp->readST01(hwp) & 0x8)) ; 901 902 VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, reg->SR31); 903 904 LEAVE(); 905} 906 907Bool 908SMILynx_CrtcPreInit(ScrnInfoPtr pScrn) 909{ 910 SMIPtr pSmi = SMIPTR(pScrn); 911 xf86CrtcPtr crtc; 912 xf86CrtcFuncsPtr crtcFuncs; 913 SMICrtcPrivatePtr crtcPriv; 914 915 ENTER(); 916 917 if(pSmi->Chipset == SMI_COUGAR3DR){ 918 /* XXX - Looking at the datasheet, it seems trivial to add 919 dualhead support for this chip... Little more than 920 splitting the WRITE_FPR/WRITE_VPR calls in separate 921 functions. Has someone access to this hardware? */ 922 923 SMI_CrtcFuncsInit_base(&crtcFuncs, &crtcPriv); 924 925 if(pSmi->useBIOS){ 926 crtcFuncs->mode_set = SMILynx_CrtcModeSet_bios; 927 }else{ 928 crtcFuncs->dpms = SMILynx_CrtcDPMS_crt; 929 crtcFuncs->mode_set = SMILynx_CrtcModeSet_vga; 930 } 931 932 crtcFuncs->mode_fixup = SMILynx_CrtcModeFixup; 933 crtcPriv->adjust_frame = SMILynx_CrtcAdjustFrame; 934 crtcPriv->video_init = SMI730_CrtcVideoInit; 935 crtcPriv->load_lut = SMILynx_CrtcLoadLUT_crt; 936 937 if(pSmi->HwCursor){ 938 crtcFuncs->set_cursor_colors = SMILynx_CrtcSetCursorColors_crt; 939 crtcFuncs->set_cursor_position = SMILynx_CrtcSetCursorPosition_crt; 940 crtcFuncs->show_cursor = SMILynx_CrtcShowCursor_crt; 941 crtcFuncs->hide_cursor = SMILynx_CrtcHideCursor_crt; 942 crtcFuncs->load_cursor_image = SMILynx_CrtcLoadCursorImage_crt; 943 } 944 945 if(! (crtc = xf86CrtcCreate(pScrn,crtcFuncs))) 946 LEAVE(FALSE); 947 crtc->driver_private = crtcPriv; 948 }else{ 949 /* CRTC0 can drive both outputs when virtual refresh is 950 disabled, and only the VGA output with virtual refresh 951 enabled. */ 952 SMI_CrtcFuncsInit_base(&crtcFuncs, &crtcPriv); 953 954 if(pSmi->useBIOS){ 955 crtcFuncs->mode_set = SMILynx_CrtcModeSet_bios; 956 }else{ 957 crtcFuncs->dpms = SMILynx_CrtcDPMS_crt; 958 959 if(pSmi->Dualhead){ 960 /* The standard VGA CRTC registers get locked in 961 virtual refresh mode. */ 962 crtcFuncs->mode_set = SMILynx_CrtcModeSet_crt; 963 964 }else{ 965 crtcFuncs->mode_set = SMILynx_CrtcModeSet_vga; 966 } 967 } 968 969 crtcFuncs->mode_fixup = SMILynx_CrtcModeFixup; 970 crtcPriv->adjust_frame = SMILynx_CrtcAdjustFrame; 971 crtcPriv->video_init = SMILynx_CrtcVideoInit_crt; 972 crtcPriv->load_lut = SMILynx_CrtcLoadLUT_crt; 973 974 if(pSmi->HwCursor){ 975 crtcFuncs->set_cursor_colors = SMILynx_CrtcSetCursorColors_crt; 976 crtcFuncs->set_cursor_position = SMILynx_CrtcSetCursorPosition_crt; 977 crtcFuncs->show_cursor = SMILynx_CrtcShowCursor_crt; 978 crtcFuncs->hide_cursor = SMILynx_CrtcHideCursor_crt; 979 crtcFuncs->load_cursor_image = SMILynx_CrtcLoadCursorImage_crt; 980 } 981 982 if(! (crtc = xf86CrtcCreate(pScrn,crtcFuncs))) 983 LEAVE(FALSE); 984 crtc->driver_private = crtcPriv; 985 986 if(pSmi->Dualhead){ 987 /* CRTC1 drives LCD when enabled. */ 988 SMI_CrtcFuncsInit_base(&crtcFuncs, &crtcPriv); 989 crtcFuncs->mode_set = SMILynx_CrtcModeSet_lcd; 990 crtcFuncs->mode_fixup = SMILynx_CrtcModeFixup; 991 crtcFuncs->dpms = SMILynx_CrtcDPMS_lcd; 992 crtcPriv->adjust_frame = SMILynx_CrtcAdjustFrame; 993 crtcPriv->video_init = SMILynx_CrtcVideoInit_lcd; 994 crtcPriv->load_lut = SMILynx_CrtcLoadLUT_lcd; 995 996 if(! (crtc = xf86CrtcCreate(pScrn,crtcFuncs))) 997 LEAVE(FALSE); 998 crtc->driver_private = crtcPriv; 999 } 1000 } 1001 1002 LEAVE(TRUE); 1003} 1004 1005