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