1/* 2 * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles 3 * 4 * Display mode initializing code 5 * 6 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria 7 * 8 * If distributed as part of the Linux kernel, this code is licensed under the 9 * terms of the GPL v2. 10 * 11 * Otherwise, the following license terms apply: 12 * 13 * * Redistribution and use in source and binary forms, with or without 14 * * modification, are permitted provided that the following conditions 15 * * are met: 16 * * 1) Redistributions of source code must retain the above copyright 17 * * notice, this list of conditions and the following disclaimer. 18 * * 2) Redistributions in binary form must reproduce the above copyright 19 * * notice, this list of conditions and the following disclaimer in the 20 * * documentation and/or other materials provided with the distribution. 21 * * 3) The name of the author may not be used to endorse or promote products 22 * * derived from this software without specific prior written permission. 23 * * 24 * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 * 35 * Author: Thomas Winischhofer <thomas@winischhofer.net> 36 * 37 */ 38 39#include <linux/module.h> 40#include <linux/kernel.h> 41#include <linux/errno.h> 42#include <linux/poll.h> 43#include <linux/init.h> 44#include <linux/slab.h> 45#include <linux/spinlock.h> 46#include <linux/kref.h> 47 48#include "sisusb.h" 49 50#ifdef INCL_SISUSB_CON 51 52#include "sisusb_init.h" 53 54/*********************************************/ 55/* POINTER INITIALIZATION */ 56/*********************************************/ 57 58static void 59SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) 60{ 61 SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo; 62 SiS_Pr->SiS_StandTable = SiSUSB_StandTable; 63 64 SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable; 65 SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable; 66 SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex; 67 SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table; 68 69 SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; 70} 71 72/*********************************************/ 73/* HELPER: Get ModeID */ 74/*********************************************/ 75 76 77/*********************************************/ 78/* HELPER: SetReg, GetReg */ 79/*********************************************/ 80 81static void 82SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port, 83 unsigned short index, unsigned short data) 84{ 85 sisusb_setidxreg(SiS_Pr->sisusb, port, index, data); 86} 87 88static void 89SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port, 90 unsigned short data) 91{ 92 sisusb_setreg(SiS_Pr->sisusb, port, data); 93} 94 95static unsigned char 96SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, 97 unsigned short index) 98{ 99 u8 data; 100 101 sisusb_getidxreg(SiS_Pr->sisusb, port, index, &data); 102 103 return data; 104} 105 106static unsigned char 107SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port) 108{ 109 u8 data; 110 111 sisusb_getreg(SiS_Pr->sisusb, port, &data); 112 113 return data; 114} 115 116static void 117SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port, 118 unsigned short index, unsigned short DataAND, 119 unsigned short DataOR) 120{ 121 sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR); 122} 123 124static void 125SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port, 126 unsigned short index, unsigned short DataAND) 127{ 128 sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND); 129} 130 131static void 132SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port, 133 unsigned short index, unsigned short DataOR) 134{ 135 sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR); 136} 137 138/*********************************************/ 139/* HELPER: DisplayOn, DisplayOff */ 140/*********************************************/ 141 142static void 143SiS_DisplayOn(struct SiS_Private *SiS_Pr) 144{ 145 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF); 146} 147 148/*********************************************/ 149/* HELPER: Init Port Addresses */ 150/*********************************************/ 151 152static void 153SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) 154{ 155 SiS_Pr->SiS_P3c4 = BaseAddr + 0x14; 156 SiS_Pr->SiS_P3d4 = BaseAddr + 0x24; 157 SiS_Pr->SiS_P3c0 = BaseAddr + 0x10; 158 SiS_Pr->SiS_P3ce = BaseAddr + 0x1e; 159 SiS_Pr->SiS_P3c2 = BaseAddr + 0x12; 160 SiS_Pr->SiS_P3ca = BaseAddr + 0x1a; 161 SiS_Pr->SiS_P3c6 = BaseAddr + 0x16; 162 SiS_Pr->SiS_P3c7 = BaseAddr + 0x17; 163 SiS_Pr->SiS_P3c8 = BaseAddr + 0x18; 164 SiS_Pr->SiS_P3c9 = BaseAddr + 0x19; 165 SiS_Pr->SiS_P3cb = BaseAddr + 0x1b; 166 SiS_Pr->SiS_P3cc = BaseAddr + 0x1c; 167 SiS_Pr->SiS_P3cd = BaseAddr + 0x1d; 168 SiS_Pr->SiS_P3da = BaseAddr + 0x2a; 169 SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04; 170} 171 172/*********************************************/ 173/* HELPER: GetSysFlags */ 174/*********************************************/ 175 176static void 177SiS_GetSysFlags(struct SiS_Private *SiS_Pr) 178{ 179 SiS_Pr->SiS_MyCR63 = 0x63; 180} 181 182/*********************************************/ 183/* HELPER: Init PCI & Engines */ 184/*********************************************/ 185 186static void 187SiSInitPCIetc(struct SiS_Private *SiS_Pr) 188{ 189 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1); 190 /* - Enable 2D (0x40) 191 * - Enable 3D (0x02) 192 * - Enable 3D vertex command fetch (0x10) 193 * - Enable 3D command parser (0x08) 194 * - Enable 3D G/L transformation engine (0x80) 195 */ 196 SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1E, 0xDA); 197} 198 199/*********************************************/ 200/* HELPER: SET SEGMENT REGISTERS */ 201/*********************************************/ 202 203static void 204SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) 205{ 206 unsigned short temp; 207 208 value &= 0x00ff; 209 temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0xf0; 210 temp |= (value >> 4); 211 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp); 212 temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0xf0; 213 temp |= (value & 0x0f); 214 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); 215} 216 217static void 218SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) 219{ 220 unsigned short temp; 221 222 value &= 0x00ff; 223 temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0x0f; 224 temp |= (value & 0xf0); 225 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp); 226 temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0x0f; 227 temp |= (value << 4); 228 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); 229} 230 231static void 232SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) 233{ 234 SiS_SetSegRegLower(SiS_Pr, value); 235 SiS_SetSegRegUpper(SiS_Pr, value); 236} 237 238static void 239SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) 240{ 241 SiS_SetSegmentReg(SiS_Pr, 0); 242} 243 244static void 245SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value) 246{ 247 unsigned short temp = value >> 8; 248 249 temp &= 0x07; 250 temp |= (temp << 4); 251 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1d, temp); 252 SiS_SetSegmentReg(SiS_Pr, value); 253} 254 255static void 256SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) 257{ 258 SiS_SetSegmentRegOver(SiS_Pr, 0); 259} 260 261static void 262SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) 263{ 264 SiS_ResetSegmentReg(SiS_Pr); 265 SiS_ResetSegmentRegOver(SiS_Pr); 266} 267 268/*********************************************/ 269/* HELPER: SearchModeID */ 270/*********************************************/ 271 272static int 273SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, 274 unsigned short *ModeIdIndex) 275{ 276 if ((*ModeNo) <= 0x13) { 277 278 if ((*ModeNo) != 0x03) 279 return 0; 280 281 (*ModeIdIndex) = 0; 282 283 } else { 284 285 for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) { 286 287 if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) 288 break; 289 290 if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF) 291 return 0; 292 } 293 294 } 295 296 return 1; 297} 298 299/*********************************************/ 300/* HELPER: ENABLE CRT1 */ 301/*********************************************/ 302 303static void 304SiS_HandleCRT1(struct SiS_Private *SiS_Pr) 305{ 306 /* Enable CRT1 gating */ 307 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf); 308} 309 310/*********************************************/ 311/* HELPER: GetColorDepth */ 312/*********************************************/ 313 314static unsigned short 315SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, 316 unsigned short ModeIdIndex) 317{ 318 static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8}; 319 unsigned short modeflag; 320 short index; 321 322 if (ModeNo <= 0x13) { 323 modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; 324 } else { 325 modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; 326 } 327 328 index = (modeflag & ModeTypeMask) - ModeEGA; 329 if (index < 0) index = 0; 330 return ColorDepth[index]; 331} 332 333/*********************************************/ 334/* HELPER: GetOffset */ 335/*********************************************/ 336 337static unsigned short 338SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, 339 unsigned short ModeIdIndex, unsigned short rrti) 340{ 341 unsigned short xres, temp, colordepth, infoflag; 342 343 infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; 344 xres = SiS_Pr->SiS_RefIndex[rrti].XRes; 345 346 colordepth = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex); 347 348 temp = xres / 16; 349 350 if (infoflag & InterlaceMode) 351 temp <<= 1; 352 353 temp *= colordepth; 354 355 if (xres % 16) 356 temp += (colordepth >> 1); 357 358 return temp; 359} 360 361/*********************************************/ 362/* SEQ */ 363/*********************************************/ 364 365static void 366SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) 367{ 368 unsigned char SRdata; 369 int i; 370 371 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x00, 0x03); 372 373 SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20; 374 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata); 375 376 for(i = 2; i <= 4; i++) { 377 SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1]; 378 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata); 379 } 380} 381 382/*********************************************/ 383/* MISC */ 384/*********************************************/ 385 386static void 387SiS_SetMiscRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) 388{ 389 unsigned char Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC; 390 391 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, Miscdata); 392} 393 394/*********************************************/ 395/* CRTC */ 396/*********************************************/ 397 398static void 399SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) 400{ 401 unsigned char CRTCdata; 402 unsigned short i; 403 404 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); 405 406 for(i = 0; i <= 0x18; i++) { 407 CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; 408 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata); 409 } 410} 411 412/*********************************************/ 413/* ATT */ 414/*********************************************/ 415 416static void 417SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) 418{ 419 unsigned char ARdata; 420 unsigned short i; 421 422 for(i = 0; i <= 0x13; i++) { 423 ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i]; 424 SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); 425 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i); 426 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, ARdata); 427 } 428 SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); 429 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x14); 430 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x00); 431 432 SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); 433 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x20); 434 SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); 435} 436 437/*********************************************/ 438/* GRC */ 439/*********************************************/ 440 441static void 442SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) 443{ 444 unsigned char GRdata; 445 unsigned short i; 446 447 for(i = 0; i <= 0x08; i++) { 448 GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i]; 449 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata); 450 } 451 452 if (SiS_Pr->SiS_ModeType > ModeVGA) { 453 /* 256 color disable */ 454 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3ce, 0x05, 0xBF); 455 } 456} 457 458/*********************************************/ 459/* CLEAR EXTENDED REGISTERS */ 460/*********************************************/ 461 462static void 463SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) 464{ 465 int i; 466 467 for(i = 0x0A; i <= 0x0E; i++) { 468 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00); 469 } 470 471 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x37, 0xFE); 472} 473 474/*********************************************/ 475/* Get rate index */ 476/*********************************************/ 477 478static unsigned short 479SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, 480 unsigned short ModeIdIndex) 481{ 482 unsigned short rrti, i, index, temp; 483 484 if (ModeNo <= 0x13) 485 return 0xFFFF; 486 487 index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F; 488 if (index > 0) index--; 489 490 rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; 491 ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID; 492 493 i = 0; 494 do { 495 if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo) 496 break; 497 498 temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask; 499 if (temp < SiS_Pr->SiS_ModeType) 500 break; 501 502 i++; 503 index--; 504 } while(index != 0xFFFF); 505 506 i--; 507 508 return (rrti + i); 509} 510 511/*********************************************/ 512/* SYNC */ 513/*********************************************/ 514 515static void 516SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) 517{ 518 unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8; 519 sync &= 0xC0; 520 sync |= 0x2f; 521 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, sync); 522} 523 524/*********************************************/ 525/* CRTC/2 */ 526/*********************************************/ 527 528static void 529SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, 530 unsigned short ModeIdIndex, unsigned short rrti) 531{ 532 unsigned char index; 533 unsigned short temp, i, j, modeflag; 534 535 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f); 536 537 modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; 538 539 index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC; 540 541 for(i = 0,j = 0; i <= 7; i++, j++) { 542 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, 543 SiS_Pr->SiS_CRT1Table[index].CR[i]); 544 } 545 for(j = 0x10; i <= 10; i++, j++) { 546 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, 547 SiS_Pr->SiS_CRT1Table[index].CR[i]); 548 } 549 for(j = 0x15; i <= 12; i++, j++) { 550 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, 551 SiS_Pr->SiS_CRT1Table[index].CR[i]); 552 } 553 for(j = 0x0A; i <= 15; i++, j++) { 554 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j, 555 SiS_Pr->SiS_CRT1Table[index].CR[i]); 556 } 557 558 temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0; 559 SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp); 560 561 temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5; 562 if (modeflag & DoubleScanMode) temp |= 0x80; 563 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp); 564 565 if (SiS_Pr->SiS_ModeType > ModeVGA) 566 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x14, 0x4F); 567} 568 569/*********************************************/ 570/* OFFSET & PITCH */ 571/*********************************************/ 572/* (partly overruled by SetPitch() in XF86) */ 573/*********************************************/ 574 575static void 576SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, 577 unsigned short ModeIdIndex, unsigned short rrti) 578{ 579 unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti); 580 unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; 581 unsigned short temp; 582 583 temp = (du >> 8) & 0x0f; 584 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, 0xF0, temp); 585 586 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF)); 587 588 if (infoflag & InterlaceMode) du >>= 1; 589 590 du <<= 5; 591 temp = (du >> 8) & 0xff; 592 if (du & 0xff) temp++; 593 temp++; 594 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp); 595} 596 597/*********************************************/ 598/* VCLK */ 599/*********************************************/ 600 601static void 602SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, 603 unsigned short rrti) 604{ 605 unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK; 606 unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B; 607 unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C; 608 609 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF); 610 611 SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka); 612 SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb); 613 SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01); 614} 615 616/*********************************************/ 617/* FIFO */ 618/*********************************************/ 619 620static void 621SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, 622 unsigned short mi) 623{ 624 unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag; 625 626 /* disable auto-threshold */ 627 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0xFE); 628 629 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0xAE); 630 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x09, 0xF0); 631 632 if (ModeNo <= 0x13) 633 return; 634 635 if ((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) { 636 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0x34); 637 SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0x01); 638 } 639} 640 641/*********************************************/ 642/* MODE REGISTERS */ 643/*********************************************/ 644 645static void 646SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, 647 unsigned short rrti) 648{ 649 unsigned short data = 0, VCLK = 0, index = 0; 650 651 if (ModeNo > 0x13) { 652 index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK; 653 VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; 654 } 655 656 if (VCLK >= 166) data |= 0x0c; 657 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data); 658 659 if (VCLK >= 166) 660 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1f, 0xe7); 661 662 /* DAC speed */ 663 data = 0x03; 664 if (VCLK >= 260) 665 data = 0x00; 666 else if (VCLK >= 160) 667 data = 0x01; 668 else if (VCLK >= 135) 669 data = 0x02; 670 671 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x07, 0xF8, data); 672} 673 674static void 675SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, 676 unsigned short ModeIdIndex, unsigned short rrti) 677{ 678 unsigned short data, infoflag = 0, modeflag; 679 680 if (ModeNo <= 0x13) 681 modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; 682 else { 683 modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; 684 infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; 685 } 686 687 /* Disable DPMS */ 688 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1F, 0x3F); 689 690 data = 0; 691 if (ModeNo > 0x13) { 692 if (SiS_Pr->SiS_ModeType > ModeEGA) { 693 data |= 0x02; 694 data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); 695 } 696 if (infoflag & InterlaceMode) data |= 0x20; 697 } 698 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data); 699 700 data = 0; 701 if (infoflag & InterlaceMode) { 702 /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */ 703 unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) | 704 ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3; 705 unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) | 706 ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5; 707 data = hrs - (hto >> 1) + 3; 708 } 709 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF)); 710 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x1a, 0xFC, (data >> 8)); 711 712 if (modeflag & HalfDCLK) 713 SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0x08); 714 715 data = 0; 716 if (modeflag & LineCompareOff) 717 data = 0x08; 718 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0xB7, data); 719 720 if ((SiS_Pr->SiS_ModeType == ModeEGA) && (ModeNo > 0x13)) 721 SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0x40); 722 723 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xfb); 724 725 data = 0x60; 726 if (SiS_Pr->SiS_ModeType != ModeText) { 727 data ^= 0x60; 728 if (SiS_Pr->SiS_ModeType != ModeEGA) 729 data ^= 0xA0; 730 } 731 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x21, 0x1F, data); 732 733 SiS_SetVCLKState(SiS_Pr, ModeNo, rrti); 734 735 if (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x31) & 0x40) 736 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x2c); 737 else 738 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x6c); 739} 740 741/*********************************************/ 742/* LOAD DAC */ 743/*********************************************/ 744 745static void 746SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData, 747 unsigned short shiftflag, unsigned short dl, unsigned short ah, 748 unsigned short al, unsigned short dh) 749{ 750 unsigned short d1, d2, d3; 751 752 switch (dl) { 753 case 0: 754 d1 = dh; d2 = ah; d3 = al; 755 break; 756 case 1: 757 d1 = ah; d2 = al; d3 = dh; 758 break; 759 default: 760 d1 = al; d2 = dh; d3 = ah; 761 } 762 SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag)); 763 SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag)); 764 SiS_SetRegByte(SiS_Pr, DACData, (d3 << shiftflag)); 765} 766 767static void 768SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi) 769{ 770 unsigned short data, data2, time, i, j, k, m, n, o; 771 unsigned short si, di, bx, sf; 772 unsigned long DACAddr, DACData; 773 const unsigned char *table = NULL; 774 775 if (ModeNo < 0x13) 776 data = SiS_Pr->SiS_SModeIDTable[mi].St_ModeFlag; 777 else 778 data = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag; 779 780 data &= DACInfoFlag; 781 782 j = time = 64; 783 if (data == 0x00) 784 table = SiS_MDA_DAC; 785 else if (data == 0x08) 786 table = SiS_CGA_DAC; 787 else if (data == 0x10) 788 table = SiS_EGA_DAC; 789 else { 790 j = 16; 791 time = 256; 792 table = SiS_VGA_DAC; 793 } 794 795 DACAddr = SiS_Pr->SiS_P3c8; 796 DACData = SiS_Pr->SiS_P3c9; 797 sf = 0; 798 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF); 799 800 SiS_SetRegByte(SiS_Pr, DACAddr, 0x00); 801 802 for(i = 0; i < j; i++) { 803 data = table[i]; 804 for(k = 0; k < 3; k++) { 805 data2 = 0; 806 if (data & 0x01) data2 += 0x2A; 807 if (data & 0x02) data2 += 0x15; 808 SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf)); 809 data >>= 2; 810 } 811 } 812 813 if (time == 256) { 814 for(i = 16; i < 32; i++) { 815 data = table[i] << sf; 816 for(k = 0; k < 3; k++) 817 SiS_SetRegByte(SiS_Pr, DACData, data); 818 } 819 si = 32; 820 for(m = 0; m < 9; m++) { 821 di = si; 822 bx = si + 4; 823 for(n = 0; n < 3; n++) { 824 for(o = 0; o < 5; o++) { 825 SiS_WriteDAC(SiS_Pr, DACData, sf, n, 826 table[di], table[bx], table[si]); 827 si++; 828 } 829 si -= 2; 830 for(o = 0; o < 3; o++) { 831 SiS_WriteDAC(SiS_Pr, DACData, sf, n, 832 table[di], table[si], table[bx]); 833 si--; 834 } 835 } 836 si += 5; 837 } 838 } 839} 840 841/*********************************************/ 842/* SET CRT1 REGISTER GROUP */ 843/*********************************************/ 844 845static void 846SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, 847 unsigned short ModeIdIndex) 848{ 849 unsigned short StandTableIndex, rrti; 850 851 SiS_Pr->SiS_CRT1Mode = ModeNo; 852 853 if (ModeNo <= 0x13) 854 StandTableIndex = 0; 855 else 856 StandTableIndex = 1; 857 858 SiS_ResetSegmentRegisters(SiS_Pr); 859 SiS_SetSeqRegs(SiS_Pr, StandTableIndex); 860 SiS_SetMiscRegs(SiS_Pr, StandTableIndex); 861 SiS_SetCRTCRegs(SiS_Pr, StandTableIndex); 862 SiS_SetATTRegs(SiS_Pr, StandTableIndex); 863 SiS_SetGRCRegs(SiS_Pr, StandTableIndex); 864 SiS_ClearExt1Regs(SiS_Pr, ModeNo); 865 866 rrti = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex); 867 868 if (rrti != 0xFFFF) { 869 SiS_SetCRT1Sync(SiS_Pr, rrti); 870 SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, rrti); 871 SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, rrti); 872 SiS_SetCRT1VCLK(SiS_Pr, ModeNo, rrti); 873 } 874 875 SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex); 876 877 SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, rrti); 878 879 SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex); 880 881 SiS_DisplayOn(SiS_Pr); 882} 883 884/*********************************************/ 885/* SiSSetMode() */ 886/*********************************************/ 887 888int 889SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) 890{ 891 unsigned short ModeIdIndex; 892 unsigned long BaseAddr = SiS_Pr->IOAddress; 893 894 SiSUSB_InitPtr(SiS_Pr); 895 SiSUSBRegInit(SiS_Pr, BaseAddr); 896 SiS_GetSysFlags(SiS_Pr); 897 898 if (!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) 899 return 0; 900 901 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x05, 0x86); 902 903 SiSInitPCIetc(SiS_Pr); 904 905 ModeNo &= 0x7f; 906 907 SiS_Pr->SiS_ModeType = 908 SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask; 909 910 SiS_Pr->SiS_SetFlag = LowModeTests; 911 912 /* Set mode on CRT1 */ 913 SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex); 914 915 SiS_HandleCRT1(SiS_Pr); 916 917 SiS_DisplayOn(SiS_Pr); 918 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF); 919 920 /* Store mode number */ 921 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x34, ModeNo); 922 923 return 1; 924} 925 926int 927SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) 928{ 929 unsigned short ModeNo = 0; 930 int i; 931 932 SiSUSB_InitPtr(SiS_Pr); 933 934 if (VModeNo == 0x03) { 935 936 ModeNo = 0x03; 937 938 } else { 939 940 i = 0; 941 do { 942 943 if (SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID == VModeNo) { 944 ModeNo = SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID; 945 break; 946 } 947 948 } while (SiS_Pr->SiS_EModeIDTable[i++].Ext_ModeID != 0xff); 949 950 } 951 952 if (!ModeNo) 953 return 0; 954 955 return SiSUSBSetMode(SiS_Pr, ModeNo); 956} 957 958#endif /* INCL_SISUSB_CON */ 959