Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
0002 /*
0003  * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
0004  *
0005  * Display mode initializing code
0006  *
0007  * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
0008  *
0009  * If distributed as part of the Linux kernel, this code is licensed under the
0010  * terms of the GPL v2.
0011  *
0012  * Otherwise, the following license terms apply:
0013  *
0014  * * Redistribution and use in source and binary forms, with or without
0015  * * modification, are permitted provided that the following conditions
0016  * * are met:
0017  * * 1) Redistributions of source code must retain the above copyright
0018  * *    notice, this list of conditions and the following disclaimer.
0019  * * 2) Redistributions in binary form must reproduce the above copyright
0020  * *    notice, this list of conditions and the following disclaimer in the
0021  * *    documentation and/or other materials provided with the distribution.
0022  * * 3) The name of the author may not be used to endorse or promote products
0023  * *    derived from this software without specific prior written permission.
0024  * *
0025  * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0026  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0027  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0028  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0029  * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0030  * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0031  * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0032  * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0033  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0034  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0035  *
0036  * Author:  Thomas Winischhofer <thomas@winischhofer.net>
0037  *
0038  */
0039 
0040 #include <linux/module.h>
0041 #include <linux/kernel.h>
0042 #include <linux/errno.h>
0043 #include <linux/poll.h>
0044 #include <linux/spinlock.h>
0045 
0046 #include "sisusb.h"
0047 #include "sisusb_init.h"
0048 #include "sisusb_tables.h"
0049 
0050 /*********************************************/
0051 /*         POINTER INITIALIZATION            */
0052 /*********************************************/
0053 
0054 static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
0055 {
0056     SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
0057     SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
0058 
0059     SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
0060     SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
0061     SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
0062     SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
0063 
0064     SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
0065 }
0066 
0067 /*********************************************/
0068 /*          HELPER: SetReg, GetReg           */
0069 /*********************************************/
0070 
0071 static void
0072 SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
0073        unsigned short index, unsigned short data)
0074 {
0075     sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
0076 }
0077 
0078 static void
0079 SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
0080            unsigned short data)
0081 {
0082     sisusb_setreg(SiS_Pr->sisusb, port, data);
0083 }
0084 
0085 static unsigned char
0086 SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index)
0087 {
0088     u8 data;
0089 
0090     sisusb_getidxreg(SiS_Pr->sisusb, port, index, &data);
0091 
0092     return data;
0093 }
0094 
0095 static unsigned char
0096 SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port)
0097 {
0098     u8 data;
0099 
0100     sisusb_getreg(SiS_Pr->sisusb, port, &data);
0101 
0102     return data;
0103 }
0104 
0105 static void
0106 SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
0107         unsigned short index, unsigned short DataAND,
0108         unsigned short DataOR)
0109 {
0110     sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
0111 }
0112 
0113 static void
0114 SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
0115           unsigned short index, unsigned short DataAND)
0116 {
0117     sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
0118 }
0119 
0120 static void
0121 SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port,
0122          unsigned short index, unsigned short DataOR)
0123 {
0124     sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
0125 }
0126 
0127 /*********************************************/
0128 /*      HELPER: DisplayOn, DisplayOff        */
0129 /*********************************************/
0130 
0131 static void SiS_DisplayOn(struct SiS_Private *SiS_Pr)
0132 {
0133     SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
0134 }
0135 
0136 /*********************************************/
0137 /*        HELPER: Init Port Addresses        */
0138 /*********************************************/
0139 
0140 static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
0141 {
0142     SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
0143     SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
0144     SiS_Pr->SiS_P3c0 = BaseAddr + 0x10;
0145     SiS_Pr->SiS_P3ce = BaseAddr + 0x1e;
0146     SiS_Pr->SiS_P3c2 = BaseAddr + 0x12;
0147     SiS_Pr->SiS_P3ca = BaseAddr + 0x1a;
0148     SiS_Pr->SiS_P3c6 = BaseAddr + 0x16;
0149     SiS_Pr->SiS_P3c7 = BaseAddr + 0x17;
0150     SiS_Pr->SiS_P3c8 = BaseAddr + 0x18;
0151     SiS_Pr->SiS_P3c9 = BaseAddr + 0x19;
0152     SiS_Pr->SiS_P3cb = BaseAddr + 0x1b;
0153     SiS_Pr->SiS_P3cc = BaseAddr + 0x1c;
0154     SiS_Pr->SiS_P3cd = BaseAddr + 0x1d;
0155     SiS_Pr->SiS_P3da = BaseAddr + 0x2a;
0156     SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04;
0157 }
0158 
0159 /*********************************************/
0160 /*             HELPER: GetSysFlags           */
0161 /*********************************************/
0162 
0163 static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
0164 {
0165     SiS_Pr->SiS_MyCR63 = 0x63;
0166 }
0167 
0168 /*********************************************/
0169 /*         HELPER: Init PCI & Engines        */
0170 /*********************************************/
0171 
0172 static void SiSInitPCIetc(struct SiS_Private *SiS_Pr)
0173 {
0174     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
0175     /*  - Enable 2D (0x40)
0176      *  - Enable 3D (0x02)
0177      *  - Enable 3D vertex command fetch (0x10)
0178      *  - Enable 3D command parser (0x08)
0179      *  - Enable 3D G/L transformation engine (0x80)
0180      */
0181     SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1E, 0xDA);
0182 }
0183 
0184 /*********************************************/
0185 /*        HELPER: SET SEGMENT REGISTERS      */
0186 /*********************************************/
0187 
0188 static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
0189 {
0190     unsigned short temp;
0191 
0192     value &= 0x00ff;
0193     temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0xf0;
0194     temp |= (value >> 4);
0195     SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp);
0196     temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0xf0;
0197     temp |= (value & 0x0f);
0198     SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
0199 }
0200 
0201 static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
0202 {
0203     unsigned short temp;
0204 
0205     value &= 0x00ff;
0206     temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0x0f;
0207     temp |= (value & 0xf0);
0208     SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp);
0209     temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0x0f;
0210     temp |= (value << 4);
0211     SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
0212 }
0213 
0214 static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
0215 {
0216     SiS_SetSegRegLower(SiS_Pr, value);
0217     SiS_SetSegRegUpper(SiS_Pr, value);
0218 }
0219 
0220 static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
0221 {
0222     SiS_SetSegmentReg(SiS_Pr, 0);
0223 }
0224 
0225 static void
0226 SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
0227 {
0228     unsigned short temp = value >> 8;
0229 
0230     temp &= 0x07;
0231     temp |= (temp << 4);
0232     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1d, temp);
0233     SiS_SetSegmentReg(SiS_Pr, value);
0234 }
0235 
0236 static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
0237 {
0238     SiS_SetSegmentRegOver(SiS_Pr, 0);
0239 }
0240 
0241 static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
0242 {
0243     SiS_ResetSegmentReg(SiS_Pr);
0244     SiS_ResetSegmentRegOver(SiS_Pr);
0245 }
0246 
0247 /*********************************************/
0248 /*           HELPER: SearchModeID            */
0249 /*********************************************/
0250 
0251 static int
0252 SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
0253          unsigned short *ModeIdIndex)
0254 {
0255     if ((*ModeNo) <= 0x13) {
0256 
0257         if ((*ModeNo) != 0x03)
0258             return 0;
0259 
0260         (*ModeIdIndex) = 0;
0261 
0262     } else {
0263 
0264         for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
0265 
0266             if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
0267                 (*ModeNo))
0268                 break;
0269 
0270             if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
0271                 0xFF)
0272                 return 0;
0273         }
0274 
0275     }
0276 
0277     return 1;
0278 }
0279 
0280 /*********************************************/
0281 /*            HELPER: ENABLE CRT1            */
0282 /*********************************************/
0283 
0284 static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
0285 {
0286     /* Enable CRT1 gating */
0287     SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
0288 }
0289 
0290 /*********************************************/
0291 /*           HELPER: GetColorDepth           */
0292 /*********************************************/
0293 
0294 static unsigned short
0295 SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
0296           unsigned short ModeIdIndex)
0297 {
0298     static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
0299     unsigned short modeflag;
0300     short index;
0301 
0302     if (ModeNo <= 0x13) {
0303         modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
0304     } else {
0305         modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
0306     }
0307 
0308     index = (modeflag & ModeTypeMask) - ModeEGA;
0309     if (index < 0)
0310         index = 0;
0311     return ColorDepth[index];
0312 }
0313 
0314 /*********************************************/
0315 /*             HELPER: GetOffset             */
0316 /*********************************************/
0317 
0318 static unsigned short
0319 SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
0320           unsigned short ModeIdIndex, unsigned short rrti)
0321 {
0322     unsigned short xres, temp, colordepth, infoflag;
0323 
0324     infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
0325     xres = SiS_Pr->SiS_RefIndex[rrti].XRes;
0326 
0327     colordepth = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex);
0328 
0329     temp = xres / 16;
0330 
0331     if (infoflag & InterlaceMode)
0332         temp <<= 1;
0333 
0334     temp *= colordepth;
0335 
0336     if (xres % 16)
0337         temp += (colordepth >> 1);
0338 
0339     return temp;
0340 }
0341 
0342 /*********************************************/
0343 /*                   SEQ                     */
0344 /*********************************************/
0345 
0346 static void
0347 SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
0348 {
0349     unsigned char SRdata;
0350     int i;
0351 
0352     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x00, 0x03);
0353 
0354     SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
0355     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
0356 
0357     for (i = 2; i <= 4; i++) {
0358         SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1];
0359         SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
0360     }
0361 }
0362 
0363 /*********************************************/
0364 /*                  MISC                     */
0365 /*********************************************/
0366 
0367 static void
0368 SiS_SetMiscRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
0369 {
0370     unsigned char Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC;
0371 
0372     SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, Miscdata);
0373 }
0374 
0375 /*********************************************/
0376 /*                  CRTC                     */
0377 /*********************************************/
0378 
0379 static void
0380 SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
0381 {
0382     unsigned char CRTCdata;
0383     unsigned short i;
0384 
0385     SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
0386 
0387     for (i = 0; i <= 0x18; i++) {
0388         CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
0389         SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
0390     }
0391 }
0392 
0393 /*********************************************/
0394 /*                   ATT                     */
0395 /*********************************************/
0396 
0397 static void
0398 SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
0399 {
0400     unsigned char ARdata;
0401     unsigned short i;
0402 
0403     for (i = 0; i <= 0x13; i++) {
0404         ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
0405         SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
0406         SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
0407         SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, ARdata);
0408     }
0409     SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
0410     SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x14);
0411     SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x00);
0412 
0413     SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
0414     SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x20);
0415     SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
0416 }
0417 
0418 /*********************************************/
0419 /*                   GRC                     */
0420 /*********************************************/
0421 
0422 static void
0423 SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
0424 {
0425     unsigned char GRdata;
0426     unsigned short i;
0427 
0428     for (i = 0; i <= 0x08; i++) {
0429         GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
0430         SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
0431     }
0432 
0433     if (SiS_Pr->SiS_ModeType > ModeVGA) {
0434         /* 256 color disable */
0435         SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3ce, 0x05, 0xBF);
0436     }
0437 }
0438 
0439 /*********************************************/
0440 /*          CLEAR EXTENDED REGISTERS         */
0441 /*********************************************/
0442 
0443 static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
0444 {
0445     int i;
0446 
0447     for (i = 0x0A; i <= 0x0E; i++) {
0448         SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
0449     }
0450 
0451     SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x37, 0xFE);
0452 }
0453 
0454 /*********************************************/
0455 /*              Get rate index               */
0456 /*********************************************/
0457 
0458 static unsigned short
0459 SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
0460            unsigned short ModeIdIndex)
0461 {
0462     unsigned short rrti, i, index, temp;
0463 
0464     if (ModeNo <= 0x13)
0465         return 0xFFFF;
0466 
0467     index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
0468     if (index > 0)
0469         index--;
0470 
0471     rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
0472     ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
0473 
0474     i = 0;
0475     do {
0476         if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
0477             break;
0478 
0479         temp =
0480             SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
0481         if (temp < SiS_Pr->SiS_ModeType)
0482             break;
0483 
0484         i++;
0485         index--;
0486     } while (index != 0xFFFF);
0487 
0488     i--;
0489 
0490     return (rrti + i);
0491 }
0492 
0493 /*********************************************/
0494 /*                  SYNC                     */
0495 /*********************************************/
0496 
0497 static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
0498 {
0499     unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
0500     sync &= 0xC0;
0501     sync |= 0x2f;
0502     SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, sync);
0503 }
0504 
0505 /*********************************************/
0506 /*                  CRTC/2                   */
0507 /*********************************************/
0508 
0509 static void
0510 SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
0511         unsigned short ModeIdIndex, unsigned short rrti)
0512 {
0513     unsigned char index;
0514     unsigned short temp, i, j, modeflag;
0515 
0516     SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
0517 
0518     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
0519 
0520     index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
0521 
0522     for (i = 0, j = 0; i <= 7; i++, j++) {
0523         SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
0524                SiS_Pr->SiS_CRT1Table[index].CR[i]);
0525     }
0526     for (j = 0x10; i <= 10; i++, j++) {
0527         SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
0528                SiS_Pr->SiS_CRT1Table[index].CR[i]);
0529     }
0530     for (j = 0x15; i <= 12; i++, j++) {
0531         SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
0532                SiS_Pr->SiS_CRT1Table[index].CR[i]);
0533     }
0534     for (j = 0x0A; i <= 15; i++, j++) {
0535         SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
0536                SiS_Pr->SiS_CRT1Table[index].CR[i]);
0537     }
0538 
0539     temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
0540     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp);
0541 
0542     temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
0543     if (modeflag & DoubleScanMode)
0544         temp |= 0x80;
0545     SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
0546 
0547     if (SiS_Pr->SiS_ModeType > ModeVGA)
0548         SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x14, 0x4F);
0549 }
0550 
0551 /*********************************************/
0552 /*               OFFSET & PITCH              */
0553 /*********************************************/
0554 /*  (partly overruled by SetPitch() in XF86) */
0555 /*********************************************/
0556 
0557 static void
0558 SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
0559           unsigned short ModeIdIndex, unsigned short rrti)
0560 {
0561     unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
0562     unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
0563     unsigned short temp;
0564 
0565     temp = (du >> 8) & 0x0f;
0566     SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, 0xF0, temp);
0567 
0568     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
0569 
0570     if (infoflag & InterlaceMode)
0571         du >>= 1;
0572 
0573     du <<= 5;
0574     temp = (du >> 8) & 0xff;
0575     if (du & 0xff)
0576         temp++;
0577     temp++;
0578     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
0579 }
0580 
0581 /*********************************************/
0582 /*                  VCLK                     */
0583 /*********************************************/
0584 
0585 static void
0586 SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
0587         unsigned short rrti)
0588 {
0589     unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
0590     unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
0591     unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
0592 
0593     SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF);
0594 
0595     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka);
0596     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb);
0597     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01);
0598 }
0599 
0600 /*********************************************/
0601 /*                  FIFO                     */
0602 /*********************************************/
0603 
0604 static void
0605 SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
0606             unsigned short mi)
0607 {
0608     unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
0609 
0610     /* disable auto-threshold */
0611     SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0xFE);
0612 
0613     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0xAE);
0614     SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x09, 0xF0);
0615 
0616     if (ModeNo <= 0x13)
0617         return;
0618 
0619     if ((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) {
0620         SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0x34);
0621         SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0x01);
0622     }
0623 }
0624 
0625 /*********************************************/
0626 /*              MODE REGISTERS               */
0627 /*********************************************/
0628 
0629 static void
0630 SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
0631          unsigned short rrti)
0632 {
0633     unsigned short data = 0, VCLK = 0, index = 0;
0634 
0635     if (ModeNo > 0x13) {
0636         index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
0637         VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
0638     }
0639 
0640     if (VCLK >= 166)
0641         data |= 0x0c;
0642     SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
0643 
0644     if (VCLK >= 166)
0645         SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1f, 0xe7);
0646 
0647     /* DAC speed */
0648     data = 0x03;
0649     if (VCLK >= 260)
0650         data = 0x00;
0651     else if (VCLK >= 160)
0652         data = 0x01;
0653     else if (VCLK >= 135)
0654         data = 0x02;
0655 
0656     SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x07, 0xF8, data);
0657 }
0658 
0659 static void
0660 SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
0661             unsigned short ModeIdIndex, unsigned short rrti)
0662 {
0663     unsigned short data, infoflag = 0, modeflag;
0664 
0665     if (ModeNo <= 0x13)
0666         modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
0667     else {
0668         modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
0669         infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
0670     }
0671 
0672     /* Disable DPMS */
0673     SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1F, 0x3F);
0674 
0675     data = 0;
0676     if (ModeNo > 0x13) {
0677         if (SiS_Pr->SiS_ModeType > ModeEGA) {
0678             data |= 0x02;
0679             data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
0680         }
0681         if (infoflag & InterlaceMode)
0682             data |= 0x20;
0683     }
0684     SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
0685 
0686     data = 0;
0687     if (infoflag & InterlaceMode) {
0688         /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
0689         unsigned short hrs =
0690             (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
0691              ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2))
0692             - 3;
0693         unsigned short hto =
0694             (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
0695              ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8))
0696             + 5;
0697         data = hrs - (hto >> 1) + 3;
0698     }
0699     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
0700     SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x1a, 0xFC, (data >> 8));
0701 
0702     if (modeflag & HalfDCLK)
0703         SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0x08);
0704 
0705     data = 0;
0706     if (modeflag & LineCompareOff)
0707         data = 0x08;
0708     SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0xB7, data);
0709 
0710     if ((SiS_Pr->SiS_ModeType == ModeEGA) && (ModeNo > 0x13))
0711         SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0x40);
0712 
0713     SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xfb);
0714 
0715     data = 0x60;
0716     if (SiS_Pr->SiS_ModeType != ModeText) {
0717         data ^= 0x60;
0718         if (SiS_Pr->SiS_ModeType != ModeEGA)
0719             data ^= 0xA0;
0720     }
0721     SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x21, 0x1F, data);
0722 
0723     SiS_SetVCLKState(SiS_Pr, ModeNo, rrti);
0724 
0725     if (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x31) & 0x40)
0726         SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x2c);
0727     else
0728         SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x6c);
0729 }
0730 
0731 /*********************************************/
0732 /*                 LOAD DAC                  */
0733 /*********************************************/
0734 
0735 static void
0736 SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
0737          unsigned short shiftflag, unsigned short dl, unsigned short ah,
0738          unsigned short al, unsigned short dh)
0739 {
0740     unsigned short d1, d2, d3;
0741 
0742     switch (dl) {
0743     case 0:
0744         d1 = dh;
0745         d2 = ah;
0746         d3 = al;
0747         break;
0748     case 1:
0749         d1 = ah;
0750         d2 = al;
0751         d3 = dh;
0752         break;
0753     default:
0754         d1 = al;
0755         d2 = dh;
0756         d3 = ah;
0757     }
0758     SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
0759     SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
0760     SiS_SetRegByte(SiS_Pr, DACData, (d3 << shiftflag));
0761 }
0762 
0763 static void
0764 SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
0765         unsigned short mi)
0766 {
0767     unsigned short data, data2, time, i, j, k, m, n, o;
0768     unsigned short si, di, bx, sf;
0769     unsigned long DACAddr, DACData;
0770     const unsigned char *table = NULL;
0771 
0772     if (ModeNo < 0x13)
0773         data = SiS_Pr->SiS_SModeIDTable[mi].St_ModeFlag;
0774     else
0775         data = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
0776 
0777     data &= DACInfoFlag;
0778 
0779     j = time = 64;
0780     if (data == 0x00)
0781         table = SiS_MDA_DAC;
0782     else if (data == 0x08)
0783         table = SiS_CGA_DAC;
0784     else if (data == 0x10)
0785         table = SiS_EGA_DAC;
0786     else {
0787         j = 16;
0788         time = 256;
0789         table = SiS_VGA_DAC;
0790     }
0791 
0792     DACAddr = SiS_Pr->SiS_P3c8;
0793     DACData = SiS_Pr->SiS_P3c9;
0794     sf = 0;
0795     SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF);
0796 
0797     SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
0798 
0799     for (i = 0; i < j; i++) {
0800         data = table[i];
0801         for (k = 0; k < 3; k++) {
0802             data2 = 0;
0803             if (data & 0x01)
0804                 data2 += 0x2A;
0805             if (data & 0x02)
0806                 data2 += 0x15;
0807             SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
0808             data >>= 2;
0809         }
0810     }
0811 
0812     if (time == 256) {
0813         for (i = 16; i < 32; i++) {
0814             data = table[i] << sf;
0815             for (k = 0; k < 3; k++)
0816                 SiS_SetRegByte(SiS_Pr, DACData, data);
0817         }
0818         si = 32;
0819         for (m = 0; m < 9; m++) {
0820             di = si;
0821             bx = si + 4;
0822             for (n = 0; n < 3; n++) {
0823                 for (o = 0; o < 5; o++) {
0824                     SiS_WriteDAC(SiS_Pr, DACData, sf, n,
0825                              table[di], table[bx],
0826                              table[si]);
0827                     si++;
0828                 }
0829                 si -= 2;
0830                 for (o = 0; o < 3; o++) {
0831                     SiS_WriteDAC(SiS_Pr, DACData, sf, n,
0832                              table[di], table[si],
0833                              table[bx]);
0834                     si--;
0835                 }
0836             }
0837             si += 5;
0838         }
0839     }
0840 }
0841 
0842 /*********************************************/
0843 /*         SET CRT1 REGISTER GROUP           */
0844 /*********************************************/
0845 
0846 static void
0847 SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
0848          unsigned short ModeIdIndex)
0849 {
0850     unsigned short StandTableIndex, rrti;
0851 
0852     SiS_Pr->SiS_CRT1Mode = ModeNo;
0853 
0854     if (ModeNo <= 0x13)
0855         StandTableIndex = 0;
0856     else
0857         StandTableIndex = 1;
0858 
0859     SiS_ResetSegmentRegisters(SiS_Pr);
0860     SiS_SetSeqRegs(SiS_Pr, StandTableIndex);
0861     SiS_SetMiscRegs(SiS_Pr, StandTableIndex);
0862     SiS_SetCRTCRegs(SiS_Pr, StandTableIndex);
0863     SiS_SetATTRegs(SiS_Pr, StandTableIndex);
0864     SiS_SetGRCRegs(SiS_Pr, StandTableIndex);
0865     SiS_ClearExt1Regs(SiS_Pr, ModeNo);
0866 
0867     rrti = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex);
0868 
0869     if (rrti != 0xFFFF) {
0870         SiS_SetCRT1Sync(SiS_Pr, rrti);
0871         SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, rrti);
0872         SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
0873         SiS_SetCRT1VCLK(SiS_Pr, ModeNo, rrti);
0874     }
0875 
0876     SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex);
0877 
0878     SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, rrti);
0879 
0880     SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex);
0881 
0882     SiS_DisplayOn(SiS_Pr);
0883 }
0884 
0885 /*********************************************/
0886 /*                 SiSSetMode()              */
0887 /*********************************************/
0888 
0889 int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
0890 {
0891     unsigned short ModeIdIndex;
0892     unsigned long BaseAddr = SiS_Pr->IOAddress;
0893 
0894     SiSUSB_InitPtr(SiS_Pr);
0895     SiSUSBRegInit(SiS_Pr, BaseAddr);
0896     SiS_GetSysFlags(SiS_Pr);
0897 
0898     if (!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex)))
0899         return 0;
0900 
0901     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x05, 0x86);
0902 
0903     SiSInitPCIetc(SiS_Pr);
0904 
0905     ModeNo &= 0x7f;
0906 
0907     SiS_Pr->SiS_ModeType =
0908         SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
0909 
0910     SiS_Pr->SiS_SetFlag = LowModeTests;
0911 
0912     /* Set mode on CRT1 */
0913     SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex);
0914 
0915     SiS_HandleCRT1(SiS_Pr);
0916 
0917     SiS_DisplayOn(SiS_Pr);
0918     SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF);
0919 
0920     /* Store mode number */
0921     SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x34, ModeNo);
0922 
0923     return 1;
0924 }
0925 
0926 int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
0927 {
0928     unsigned short ModeNo = 0;
0929     int i;
0930 
0931     SiSUSB_InitPtr(SiS_Pr);
0932 
0933     if (VModeNo == 0x03) {
0934 
0935         ModeNo = 0x03;
0936 
0937     } else {
0938 
0939         i = 0;
0940         do {
0941 
0942             if (SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID == VModeNo) {
0943                 ModeNo = SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID;
0944                 break;
0945             }
0946 
0947         } while (SiS_Pr->SiS_EModeIDTable[i++].Ext_ModeID != 0xff);
0948 
0949     }
0950 
0951     if (!ModeNo)
0952         return 0;
0953 
0954     return SiSUSBSetMode(SiS_Pr, ModeNo);
0955 }