Showing error 1864

User: Jiri Slaby
Error type: Invalid Pointer Dereference
Error type description: A pointer which is invalid is being dereferenced
File location: drivers/video/sis/sis_main.c
Line in file: 4481
Project: Linux Kernel
Project version: 2.6.28
Tools: Smatch (1.59)
Entered: 2013-09-11 08:47:26 UTC


Source:

   1/*
   2 * SiS 300/540/630[S]/730[S],
   3 * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX],
   4 * XGI V3XT/V5/V8, Z7
   5 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
   6 *
   7 * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the named License,
  12 * or any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
  22 *
  23 * Author:        Thomas Winischhofer <thomas@winischhofer.net>
  24 *
  25 * Author of (practically wiped) code base:
  26 *                SiS (www.sis.com)
  27 *                Copyright (C) 1999 Silicon Integrated Systems, Inc.
  28 *
  29 * See http://www.winischhofer.net/ for more information and updates
  30 *
  31 * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
  32 * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
  33 *
  34 */
  35
  36#include <linux/module.h>
  37#include <linux/moduleparam.h>
  38#include <linux/kernel.h>
  39#include <linux/spinlock.h>
  40#include <linux/errno.h>
  41#include <linux/string.h>
  42#include <linux/mm.h>
  43#include <linux/screen_info.h>
  44#include <linux/slab.h>
  45#include <linux/fb.h>
  46#include <linux/selection.h>
  47#include <linux/ioport.h>
  48#include <linux/init.h>
  49#include <linux/pci.h>
  50#include <linux/vmalloc.h>
  51#include <linux/capability.h>
  52#include <linux/fs.h>
  53#include <linux/types.h>
  54#include <linux/uaccess.h>
  55#include <asm/io.h>
  56#ifdef CONFIG_MTRR
  57#include <asm/mtrr.h>
  58#endif
  59
  60#include "sis.h"
  61#include "sis_main.h"
  62
  63static void sisfb_handle_command(struct sis_video_info *ivideo,
  64                                 struct sisfb_cmd *sisfb_command);
  65
  66/* ------------------ Internal helper routines ----------------- */
  67
  68static void __init
  69sisfb_setdefaultparms(void)
  70{
  71        sisfb_off                = 0;
  72        sisfb_parm_mem                = 0;
  73        sisfb_accel                = -1;
  74        sisfb_ypan                = -1;
  75        sisfb_max                = -1;
  76        sisfb_userom                = -1;
  77        sisfb_useoem                = -1;
  78        sisfb_mode_idx                = -1;
  79        sisfb_parm_rate                = -1;
  80        sisfb_crt1off                = 0;
  81        sisfb_forcecrt1                = -1;
  82        sisfb_crt2type                = -1;
  83        sisfb_crt2flags                = 0;
  84        sisfb_pdc                = 0xff;
  85        sisfb_pdca                = 0xff;
  86        sisfb_scalelcd                = -1;
  87        sisfb_specialtiming         = CUT_NONE;
  88        sisfb_lvdshl                = -1;
  89        sisfb_dstn                = 0;
  90        sisfb_fstn                = 0;
  91        sisfb_tvplug                = -1;
  92        sisfb_tvstd                = -1;
  93        sisfb_tvxposoffset        = 0;
  94        sisfb_tvyposoffset        = 0;
  95        sisfb_nocrt2rate        = 0;
  96#if !defined(__i386__) && !defined(__x86_64__)
  97        sisfb_resetcard                = 0;
  98        sisfb_videoram                = 0;
  99#endif
 100}
 101
 102/* ------------- Parameter parsing -------------- */
 103
 104static void __devinit
 105sisfb_search_vesamode(unsigned int vesamode, bool quiet)
 106{
 107        int i = 0, j = 0;
 108
 109        /* We don't know the hardware specs yet and there is no ivideo */
 110
 111        if(vesamode == 0) {
 112                if(!quiet)
 113                        printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
 114
 115                sisfb_mode_idx = DEFAULT_MODE;
 116
 117                return;
 118        }
 119
 120        vesamode &= 0x1dff;  /* Clean VESA mode number from other flags */
 121
 122        while(sisbios_mode[i++].mode_no[0] != 0) {
 123                if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
 124                    (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
 125                        if(sisfb_fstn) {
 126                                if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
 127                                   sisbios_mode[i-1].mode_no[1] == 0x56 ||
 128                                   sisbios_mode[i-1].mode_no[1] == 0x53)
 129                                        continue;
 130                        } else {
 131                                if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
 132                                   sisbios_mode[i-1].mode_no[1] == 0x5b)
 133                                        continue;
 134                        }
 135                        sisfb_mode_idx = i - 1;
 136                        j = 1;
 137                        break;
 138                }
 139        }
 140        if((!j) && !quiet)
 141                printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
 142}
 143
 144static void __devinit
 145sisfb_search_mode(char *name, bool quiet)
 146{
 147        unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
 148        int i = 0;
 149        char strbuf[16], strbuf1[20];
 150        char *nameptr = name;
 151
 152        /* We don't know the hardware specs yet and there is no ivideo */
 153
 154        if(name == NULL) {
 155                if(!quiet)
 156                        printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
 157
 158                sisfb_mode_idx = DEFAULT_MODE;
 159                return;
 160        }
 161
 162        if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
 163                if(!quiet)
 164                        printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
 165
 166                sisfb_mode_idx = DEFAULT_MODE;
 167                return;
 168        }
 169
 170        if(strlen(name) <= 19) {
 171                strcpy(strbuf1, name);
 172                for(i = 0; i < strlen(strbuf1); i++) {
 173                        if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
 174                }
 175
 176                /* This does some fuzzy mode naming detection */
 177                if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
 178                        if((rate <= 32) || (depth > 32)) {
 179                                j = rate; rate = depth; depth = j;
 180                        }
 181                        sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
 182                        nameptr = strbuf;
 183                        sisfb_parm_rate = rate;
 184                } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
 185                        sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
 186                        nameptr = strbuf;
 187                } else {
 188                        xres = 0;
 189                        if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
 190                                sprintf(strbuf, "%ux%ux8", xres, yres);
 191                                nameptr = strbuf;
 192                        } else {
 193                                sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
 194                                return;
 195                        }
 196                }
 197        }
 198
 199        i = 0; j = 0;
 200        while(sisbios_mode[i].mode_no[0] != 0) {
 201                if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
 202                        if(sisfb_fstn) {
 203                                if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
 204                                   sisbios_mode[i-1].mode_no[1] == 0x56 ||
 205                                   sisbios_mode[i-1].mode_no[1] == 0x53)
 206                                        continue;
 207                        } else {
 208                                if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
 209                                   sisbios_mode[i-1].mode_no[1] == 0x5b)
 210                                        continue;
 211                        }
 212                        sisfb_mode_idx = i - 1;
 213                        j = 1;
 214                        break;
 215                }
 216        }
 217
 218        if((!j) && !quiet)
 219                printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
 220}
 221
 222#ifndef MODULE
 223static void __devinit
 224sisfb_get_vga_mode_from_kernel(void)
 225{
 226#ifdef CONFIG_X86
 227        char mymode[32];
 228        int  mydepth = screen_info.lfb_depth;
 229
 230        if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
 231
 232        if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
 233            (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
 234            (mydepth >= 8) && (mydepth <= 32) ) {
 235
 236                if(mydepth == 24) mydepth = 32;
 237
 238                sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
 239                                        screen_info.lfb_height,
 240                                        mydepth);
 241
 242                printk(KERN_DEBUG
 243                        "sisfb: Using vga mode %s pre-set by kernel as default\n",
 244                        mymode);
 245
 246                sisfb_search_mode(mymode, true);
 247        }
 248#endif
 249        return;
 250}
 251#endif
 252
 253static void __init
 254sisfb_search_crt2type(const char *name)
 255{
 256        int i = 0;
 257
 258        /* We don't know the hardware specs yet and there is no ivideo */
 259
 260        if(name == NULL) return;
 261
 262        while(sis_crt2type[i].type_no != -1) {
 263                if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
 264                        sisfb_crt2type = sis_crt2type[i].type_no;
 265                        sisfb_tvplug = sis_crt2type[i].tvplug_no;
 266                        sisfb_crt2flags = sis_crt2type[i].flags;
 267                        break;
 268                }
 269                i++;
 270        }
 271
 272        sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
 273        sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
 274
 275        if(sisfb_crt2type < 0)
 276                printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
 277}
 278
 279static void __init
 280sisfb_search_tvstd(const char *name)
 281{
 282        int i = 0;
 283
 284        /* We don't know the hardware specs yet and there is no ivideo */
 285
 286        if(name == NULL)
 287                return;
 288
 289        while(sis_tvtype[i].type_no != -1) {
 290                if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
 291                        sisfb_tvstd = sis_tvtype[i].type_no;
 292                        break;
 293                }
 294                i++;
 295        }
 296}
 297
 298static void __init
 299sisfb_search_specialtiming(const char *name)
 300{
 301        int i = 0;
 302        bool found = false;
 303
 304        /* We don't know the hardware specs yet and there is no ivideo */
 305
 306        if(name == NULL)
 307                return;
 308
 309        if(!strnicmp(name, "none", 4)) {
 310                sisfb_specialtiming = CUT_FORCENONE;
 311                printk(KERN_DEBUG "sisfb: Special timing disabled\n");
 312        } else {
 313                while(mycustomttable[i].chipID != 0) {
 314                        if(!strnicmp(name,mycustomttable[i].optionName,
 315                           strlen(mycustomttable[i].optionName))) {
 316                                sisfb_specialtiming = mycustomttable[i].SpecialID;
 317                                found = true;
 318                                printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
 319                                        mycustomttable[i].vendorName,
 320                                        mycustomttable[i].cardName,
 321                                        mycustomttable[i].optionName);
 322                                break;
 323                        }
 324                        i++;
 325                }
 326                if(!found) {
 327                        printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
 328                        printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
 329                        i = 0;
 330                        while(mycustomttable[i].chipID != 0) {
 331                                printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
 332                                        mycustomttable[i].optionName,
 333                                        mycustomttable[i].vendorName,
 334                                        mycustomttable[i].cardName);
 335                                i++;
 336                        }
 337                }
 338        }
 339}
 340
 341/* ----------- Various detection routines ----------- */
 342
 343static void __devinit
 344sisfb_detect_custom_timing(struct sis_video_info *ivideo)
 345{
 346        unsigned char *biosver = NULL;
 347        unsigned char *biosdate = NULL;
 348        bool footprint;
 349        u32 chksum = 0;
 350        int i, j;
 351
 352        if(ivideo->SiS_Pr.UseROM) {
 353                biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
 354                biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
 355                for(i = 0; i < 32768; i++)
 356                        chksum += ivideo->SiS_Pr.VirtualRomBase[i];
 357        }
 358
 359        i = 0;
 360        do {
 361                if( (mycustomttable[i].chipID == ivideo->chip)                        &&
 362                    ((!strlen(mycustomttable[i].biosversion)) ||
 363                     (ivideo->SiS_Pr.UseROM &&
 364                      (!strncmp(mycustomttable[i].biosversion, biosver,
 365                                strlen(mycustomttable[i].biosversion)))))        &&
 366                    ((!strlen(mycustomttable[i].biosdate)) ||
 367                     (ivideo->SiS_Pr.UseROM &&
 368                      (!strncmp(mycustomttable[i].biosdate, biosdate,
 369                                strlen(mycustomttable[i].biosdate)))))                &&
 370                    ((!mycustomttable[i].bioschksum) ||
 371                     (ivideo->SiS_Pr.UseROM &&
 372                      (mycustomttable[i].bioschksum == chksum)))                &&
 373                    (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
 374                    (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
 375                        footprint = true;
 376                        for(j = 0; j < 5; j++) {
 377                                if(mycustomttable[i].biosFootprintAddr[j]) {
 378                                        if(ivideo->SiS_Pr.UseROM) {
 379                                                if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
 380                                                        mycustomttable[i].biosFootprintData[j]) {
 381                                                        footprint = false;
 382                                                }
 383                                        } else
 384                                                footprint = false;
 385                                }
 386                        }
 387                        if(footprint) {
 388                                ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
 389                                printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
 390                                        mycustomttable[i].vendorName,
 391                                mycustomttable[i].cardName);
 392                                printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
 393                                        mycustomttable[i].optionName);
 394                                break;
 395                        }
 396                }
 397                i++;
 398        } while(mycustomttable[i].chipID);
 399}
 400
 401static bool __devinit
 402sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
 403{
 404        int i, j, xres, yres, refresh, index;
 405        u32 emodes;
 406
 407        if(buffer[0] != 0x00 || buffer[1] != 0xff ||
 408           buffer[2] != 0xff || buffer[3] != 0xff ||
 409           buffer[4] != 0xff || buffer[5] != 0xff ||
 410           buffer[6] != 0xff || buffer[7] != 0x00) {
 411                printk(KERN_DEBUG "sisfb: Bad EDID header\n");
 412                return false;
 413        }
 414
 415        if(buffer[0x12] != 0x01) {
 416                printk(KERN_INFO "sisfb: EDID version %d not supported\n",
 417                        buffer[0x12]);
 418                return false;
 419        }
 420
 421        monitor->feature = buffer[0x18];
 422
 423        if(!(buffer[0x14] & 0x80)) {
 424                if(!(buffer[0x14] & 0x08)) {
 425                        printk(KERN_INFO
 426                                "sisfb: WARNING: Monitor does not support separate syncs\n");
 427                }
 428        }
 429
 430        if(buffer[0x13] >= 0x01) {
 431           /* EDID V1 rev 1 and 2: Search for monitor descriptor
 432            * to extract ranges
 433            */
 434            j = 0x36;
 435            for(i=0; i<4; i++) {
 436               if(buffer[j]     == 0x00 && buffer[j + 1] == 0x00 &&
 437                  buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
 438                  buffer[j + 4] == 0x00) {
 439                  monitor->hmin = buffer[j + 7];
 440                  monitor->hmax = buffer[j + 8];
 441                  monitor->vmin = buffer[j + 5];
 442                  monitor->vmax = buffer[j + 6];
 443                  monitor->dclockmax = buffer[j + 9] * 10 * 1000;
 444                  monitor->datavalid = true;
 445                  break;
 446               }
 447               j += 18;
 448            }
 449        }
 450
 451        if(!monitor->datavalid) {
 452           /* Otherwise: Get a range from the list of supported
 453            * Estabished Timings. This is not entirely accurate,
 454            * because fixed frequency monitors are not supported
 455            * that way.
 456            */
 457           monitor->hmin = 65535; monitor->hmax = 0;
 458           monitor->vmin = 65535; monitor->vmax = 0;
 459           monitor->dclockmax = 0;
 460           emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
 461           for(i = 0; i < 13; i++) {
 462              if(emodes & sisfb_ddcsmodes[i].mask) {
 463                 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
 464                 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
 465                 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
 466                 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
 467                 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
 468              }
 469           }
 470           index = 0x26;
 471           for(i = 0; i < 8; i++) {
 472              xres = (buffer[index] + 31) * 8;
 473              switch(buffer[index + 1] & 0xc0) {
 474                 case 0xc0: yres = (xres * 9) / 16; break;
 475                 case 0x80: yres = (xres * 4) /  5; break;
 476                 case 0x40: yres = (xres * 3) /  4; break;
 477                 default:   yres = xres;            break;
 478              }
 479              refresh = (buffer[index + 1] & 0x3f) + 60;
 480              if((xres >= 640) && (yres >= 480)) {
 481                 for(j = 0; j < 8; j++) {
 482                    if((xres == sisfb_ddcfmodes[j].x) &&
 483                       (yres == sisfb_ddcfmodes[j].y) &&
 484                       (refresh == sisfb_ddcfmodes[j].v)) {
 485                      if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
 486                      if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
 487                      if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
 488                      if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
 489                      if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
 490                    }
 491                 }
 492              }
 493              index += 2;
 494           }
 495           if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
 496              monitor->datavalid = true;
 497           }
 498        }
 499
 500        return monitor->datavalid;
 501}
 502
 503static void __devinit
 504sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
 505{
 506        unsigned short temp, i, realcrtno = crtno;
 507        unsigned char  buffer[256];
 508
 509        monitor->datavalid = false;
 510
 511        if(crtno) {
 512           if(ivideo->vbflags & CRT2_LCD)      realcrtno = 1;
 513           else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
 514           else return;
 515        }
 516
 517        if((ivideo->sisfb_crt1off) && (!crtno))
 518                return;
 519
 520        temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
 521                                realcrtno, 0, &buffer[0], ivideo->vbflags2);
 522        if((!temp) || (temp == 0xffff)) {
 523           printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
 524           return;
 525        } else {
 526           printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
 527           printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
 528                crtno + 1,
 529                (temp & 0x1a) ? "" : "[none of the supported]",
 530                (temp & 0x02) ? "2 " : "",
 531                (temp & 0x08) ? "D&P" : "",
 532                (temp & 0x10) ? "FPDI-2" : "");
 533           if(temp & 0x02) {
 534              i = 3;  /* Number of retrys */
 535              do {
 536                 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
 537                                     realcrtno, 1, &buffer[0], ivideo->vbflags2);
 538              } while((temp) && i--);
 539              if(!temp) {
 540                 if(sisfb_interpret_edid(monitor, &buffer[0])) {
 541                    printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
 542                        monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
 543                        monitor->dclockmax / 1000);
 544                 } else {
 545                    printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
 546                 }
 547              } else {
 548                 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
 549              }
 550           } else {
 551              printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
 552           }
 553        }
 554}
 555
 556/* -------------- Mode validation --------------- */
 557
 558static bool
 559sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
 560                int mode_idx, int rate_idx, int rate)
 561{
 562        int htotal, vtotal;
 563        unsigned int dclock, hsync;
 564
 565        if(!monitor->datavalid)
 566                return true;
 567
 568        if(mode_idx < 0)
 569                return false;
 570
 571        /* Skip for 320x200, 320x240, 640x400 */
 572        switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
 573        case 0x59:
 574        case 0x41:
 575        case 0x4f:
 576        case 0x50:
 577        case 0x56:
 578        case 0x53:
 579        case 0x2f:
 580        case 0x5d:
 581        case 0x5e:
 582                return true;
 583#ifdef CONFIG_FB_SIS_315
 584        case 0x5a:
 585        case 0x5b:
 586                if(ivideo->sisvga_engine == SIS_315_VGA) return true;
 587#endif
 588        }
 589
 590        if(rate < (monitor->vmin - 1))
 591                return false;
 592        if(rate > (monitor->vmax + 1))
 593                return false;
 594
 595        if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
 596                                  sisbios_mode[mode_idx].mode_no[ivideo->mni],
 597                                  &htotal, &vtotal, rate_idx)) {
 598                dclock = (htotal * vtotal * rate) / 1000;
 599                if(dclock > (monitor->dclockmax + 1000))
 600                        return false;
 601                hsync = dclock / htotal;
 602                if(hsync < (monitor->hmin - 1))
 603                        return false;
 604                if(hsync > (monitor->hmax + 1))
 605                        return false;
 606        } else {
 607                return false;
 608        }
 609        return true;
 610}
 611
 612static int
 613sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
 614{
 615        u16 xres=0, yres, myres;
 616
 617#ifdef CONFIG_FB_SIS_300
 618        if(ivideo->sisvga_engine == SIS_300_VGA) {
 619                if(!(sisbios_mode[myindex].chipset & MD_SIS300))
 620                        return -1 ;
 621        }
 622#endif
 623#ifdef CONFIG_FB_SIS_315
 624        if(ivideo->sisvga_engine == SIS_315_VGA) {
 625                if(!(sisbios_mode[myindex].chipset & MD_SIS315))
 626                        return -1;
 627        }
 628#endif
 629
 630        myres = sisbios_mode[myindex].yres;
 631
 632        switch(vbflags & VB_DISPTYPE_DISP2) {
 633
 634        case CRT2_LCD:
 635                xres = ivideo->lcdxres; yres = ivideo->lcdyres;
 636
 637                if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
 638                   (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
 639                        if(sisbios_mode[myindex].xres > xres)
 640                                return -1;
 641                        if(myres > yres)
 642                                return -1;
 643                }
 644
 645                if(ivideo->sisfb_fstn) {
 646                        if(sisbios_mode[myindex].xres == 320) {
 647                                if(myres == 240) {
 648                                        switch(sisbios_mode[myindex].mode_no[1]) {
 649                                                case 0x50: myindex = MODE_FSTN_8;  break;
 650                                                case 0x56: myindex = MODE_FSTN_16; break;
 651                                                case 0x53: return -1;
 652                                        }
 653                                }
 654                        }
 655                }
 656
 657                if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
 658                                 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
 659                                 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
 660                        return -1;
 661                }
 662                break;
 663
 664        case CRT2_TV:
 665                if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
 666                                sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
 667                        return -1;
 668                }
 669                break;
 670
 671        case CRT2_VGA:
 672                if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
 673                                sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
 674                        return -1;
 675                }
 676                break;
 677        }
 678
 679        return myindex;
 680}
 681
 682static u8
 683sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
 684{
 685        int i = 0;
 686        u16 xres = sisbios_mode[mode_idx].xres;
 687        u16 yres = sisbios_mode[mode_idx].yres;
 688
 689        ivideo->rate_idx = 0;
 690        while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
 691                if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
 692                        if(sisfb_vrate[i].refresh == rate) {
 693                                ivideo->rate_idx = sisfb_vrate[i].idx;
 694                                break;
 695                        } else if(sisfb_vrate[i].refresh > rate) {
 696                                if((sisfb_vrate[i].refresh - rate) <= 3) {
 697                                        DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
 698                                                rate, sisfb_vrate[i].refresh);
 699                                        ivideo->rate_idx = sisfb_vrate[i].idx;
 700                                        ivideo->refresh_rate = sisfb_vrate[i].refresh;
 701                                } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
 702                                                && (sisfb_vrate[i].idx != 1)) {
 703                                        DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
 704                                                rate, sisfb_vrate[i-1].refresh);
 705                                        ivideo->rate_idx = sisfb_vrate[i-1].idx;
 706                                        ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
 707                                }
 708                                break;
 709                        } else if((rate - sisfb_vrate[i].refresh) <= 2) {
 710                                DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
 711                                                rate, sisfb_vrate[i].refresh);
 712                                ivideo->rate_idx = sisfb_vrate[i].idx;
 713                                break;
 714                        }
 715                }
 716                i++;
 717        }
 718        if(ivideo->rate_idx > 0) {
 719                return ivideo->rate_idx;
 720        } else {
 721                printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
 722                                rate, xres, yres);
 723                return 0;
 724        }
 725}
 726
 727static bool
 728sisfb_bridgeisslave(struct sis_video_info *ivideo)
 729{
 730        unsigned char P1_00;
 731
 732        if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
 733                return false;
 734
 735        inSISIDXREG(SISPART1,0x00,P1_00);
 736        if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
 737            ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
 738                return true;
 739        } else {
 740                return false;
 741        }
 742}
 743
 744static bool
 745sisfballowretracecrt1(struct sis_video_info *ivideo)
 746{
 747        u8 temp;
 748
 749        inSISIDXREG(SISCR,0x17,temp);
 750        if(!(temp & 0x80))
 751                return false;
 752
 753        inSISIDXREG(SISSR,0x1f,temp);
 754        if(temp & 0xc0)
 755                return false;
 756
 757        return true;
 758}
 759
 760static bool
 761sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
 762{
 763        if(!sisfballowretracecrt1(ivideo))
 764                return false;
 765
 766        if(inSISREG(SISINPSTAT) & 0x08)
 767                return true;
 768        else
 769                return false;
 770}
 771
 772static void
 773sisfbwaitretracecrt1(struct sis_video_info *ivideo)
 774{
 775        int watchdog;
 776
 777        if(!sisfballowretracecrt1(ivideo))
 778                return;
 779
 780        watchdog = 65536;
 781        while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
 782        watchdog = 65536;
 783        while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
 784}
 785
 786static bool
 787sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
 788{
 789        unsigned char temp, reg;
 790
 791        switch(ivideo->sisvga_engine) {
 792        case SIS_300_VGA: reg = 0x25; break;
 793        case SIS_315_VGA: reg = 0x30; break;
 794        default:          return false;
 795        }
 796
 797        inSISIDXREG(SISPART1, reg, temp);
 798        if(temp & 0x02)
 799                return true;
 800        else
 801                return false;
 802}
 803
 804static bool
 805sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
 806{
 807        if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
 808                if(!sisfb_bridgeisslave(ivideo)) {
 809                        return sisfbcheckvretracecrt2(ivideo);
 810                }
 811        }
 812        return sisfbcheckvretracecrt1(ivideo);
 813}
 814
 815static u32
 816sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
 817{
 818        u8 idx, reg1, reg2, reg3, reg4;
 819        u32 ret = 0;
 820
 821        (*vcount) = (*hcount) = 0;
 822
 823        if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
 824
 825                ret |= (FB_VBLANK_HAVE_VSYNC  |
 826                        FB_VBLANK_HAVE_HBLANK |
 827                        FB_VBLANK_HAVE_VBLANK |
 828                        FB_VBLANK_HAVE_VCOUNT |
 829                        FB_VBLANK_HAVE_HCOUNT);
 830                switch(ivideo->sisvga_engine) {
 831                        case SIS_300_VGA: idx = 0x25; break;
 832                        default:
 833                        case SIS_315_VGA: idx = 0x30; break;
 834                }
 835                inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
 836                inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
 837                inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
 838                inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
 839                if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
 840                if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
 841                if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
 842                (*vcount) = reg3 | ((reg4 & 0x70) << 4);
 843                (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
 844
 845        } else if(sisfballowretracecrt1(ivideo)) {
 846
 847                ret |= (FB_VBLANK_HAVE_VSYNC  |
 848                        FB_VBLANK_HAVE_VBLANK |
 849                        FB_VBLANK_HAVE_VCOUNT |
 850                        FB_VBLANK_HAVE_HCOUNT);
 851                reg1 = inSISREG(SISINPSTAT);
 852                if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
 853                if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
 854                inSISIDXREG(SISCR,0x20,reg1);
 855                inSISIDXREG(SISCR,0x1b,reg1);
 856                inSISIDXREG(SISCR,0x1c,reg2);
 857                inSISIDXREG(SISCR,0x1d,reg3);
 858                (*vcount) = reg2 | ((reg3 & 0x07) << 8);
 859                (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
 860        }
 861
 862        return ret;
 863}
 864
 865static int
 866sisfb_myblank(struct sis_video_info *ivideo, int blank)
 867{
 868        u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
 869        bool backlight = true;
 870
 871        switch(blank) {
 872                case FB_BLANK_UNBLANK:        /* on */
 873                        sr01  = 0x00;
 874                        sr11  = 0x00;
 875                        sr1f  = 0x00;
 876                        cr63  = 0x00;
 877                        p2_0  = 0x20;
 878                        p1_13 = 0x00;
 879                        backlight = true;
 880                        break;
 881                case FB_BLANK_NORMAL:        /* blank */
 882                        sr01  = 0x20;
 883                        sr11  = 0x00;
 884                        sr1f  = 0x00;
 885                        cr63  = 0x00;
 886                        p2_0  = 0x20;
 887                        p1_13 = 0x00;
 888                        backlight = true;
 889                        break;
 890                case FB_BLANK_VSYNC_SUSPEND:        /* no vsync */
 891                        sr01  = 0x20;
 892                        sr11  = 0x08;
 893                        sr1f  = 0x80;
 894                        cr63  = 0x40;
 895                        p2_0  = 0x40;
 896                        p1_13 = 0x80;
 897                        backlight = false;
 898                        break;
 899                case FB_BLANK_HSYNC_SUSPEND:        /* no hsync */
 900                        sr01  = 0x20;
 901                        sr11  = 0x08;
 902                        sr1f  = 0x40;
 903                        cr63  = 0x40;
 904                        p2_0  = 0x80;
 905                        p1_13 = 0x40;
 906                        backlight = false;
 907                        break;
 908                case FB_BLANK_POWERDOWN:        /* off */
 909                        sr01  = 0x20;
 910                        sr11  = 0x08;
 911                        sr1f  = 0xc0;
 912                        cr63  = 0x40;
 913                        p2_0  = 0xc0;
 914                        p1_13 = 0xc0;
 915                        backlight = false;
 916                        break;
 917                default:
 918                        return 1;
 919        }
 920
 921        if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
 922
 923                if( (!ivideo->sisfb_thismonitor.datavalid) ||
 924                    ((ivideo->sisfb_thismonitor.datavalid) &&
 925                     (ivideo->sisfb_thismonitor.feature & 0xe0))) {
 926
 927                        if(ivideo->sisvga_engine == SIS_315_VGA) {
 928                                setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
 929                        }
 930
 931                        if(!(sisfb_bridgeisslave(ivideo))) {
 932                                setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
 933                                setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
 934                        }
 935                }
 936
 937        }
 938
 939        if(ivideo->currentvbflags & CRT2_LCD) {
 940
 941                if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
 942                        if(backlight) {
 943                                SiS_SiS30xBLOn(&ivideo->SiS_Pr);
 944                        } else {
 945                                SiS_SiS30xBLOff(&ivideo->SiS_Pr);
 946                        }
 947                } else if(ivideo->sisvga_engine == SIS_315_VGA) {
 948#ifdef CONFIG_FB_SIS_315
 949                        if(ivideo->vbflags2 & VB2_CHRONTEL) {
 950                                if(backlight) {
 951                                        SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
 952                                } else {
 953                                        SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
 954                                }
 955                        }
 956#endif
 957                }
 958
 959                if(((ivideo->sisvga_engine == SIS_300_VGA) &&
 960                    (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
 961                   ((ivideo->sisvga_engine == SIS_315_VGA) &&
 962                    ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
 963                        setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
 964                }
 965
 966                if(ivideo->sisvga_engine == SIS_300_VGA) {
 967                        if((ivideo->vbflags2 & VB2_30xB) &&
 968                           (!(ivideo->vbflags2 & VB2_30xBDH))) {
 969                                setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
 970                        }
 971                } else if(ivideo->sisvga_engine == SIS_315_VGA) {
 972                        if((ivideo->vbflags2 & VB2_30xB) &&
 973                           (!(ivideo->vbflags2 & VB2_30xBDH))) {
 974                                setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
 975                        }
 976                }
 977
 978        } else if(ivideo->currentvbflags & CRT2_VGA) {
 979
 980                if(ivideo->vbflags2 & VB2_30xB) {
 981                        setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
 982                }
 983
 984        }
 985
 986        return 0;
 987}
 988
 989/* ------------- Callbacks from init.c/init301.c  -------------- */
 990
 991#ifdef CONFIG_FB_SIS_300
 992unsigned int
 993sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
 994{
 995   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
 996   u32 val = 0;
 997
 998   pci_read_config_dword(ivideo->nbridge, reg, &val);
 999   return (unsigned int)val;
1000}
1001
1002void
1003sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1004{
1005   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1006
1007   pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1008}
1009
1010unsigned int
1011sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1012{
1013   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1014   u32 val = 0;
1015
1016   if(!ivideo->lpcdev) return 0;
1017
1018   pci_read_config_dword(ivideo->lpcdev, reg, &val);
1019   return (unsigned int)val;
1020}
1021#endif
1022
1023#ifdef CONFIG_FB_SIS_315
1024void
1025sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1026{
1027   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1028
1029   pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1030}
1031
1032unsigned int
1033sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1034{
1035   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1036   u16 val = 0;
1037
1038   if(!ivideo->lpcdev) return 0;
1039
1040   pci_read_config_word(ivideo->lpcdev, reg, &val);
1041   return (unsigned int)val;
1042}
1043#endif
1044
1045/* ----------- FBDev related routines for all series ----------- */
1046
1047static int
1048sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1049{
1050        return (var->bits_per_pixel == 8) ? 256 : 16;
1051}
1052
1053static void
1054sisfb_set_vparms(struct sis_video_info *ivideo)
1055{
1056        switch(ivideo->video_bpp) {
1057        case 8:
1058                ivideo->DstColor = 0x0000;
1059                ivideo->SiS310_AccelDepth = 0x00000000;
1060                ivideo->video_cmap_len = 256;
1061                break;
1062        case 16:
1063                ivideo->DstColor = 0x8000;
1064                ivideo->SiS310_AccelDepth = 0x00010000;
1065                ivideo->video_cmap_len = 16;
1066                break;
1067        case 32:
1068                ivideo->DstColor = 0xC000;
1069                ivideo->SiS310_AccelDepth = 0x00020000;
1070                ivideo->video_cmap_len = 16;
1071                break;
1072        default:
1073                ivideo->video_cmap_len = 16;
1074                printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1075                ivideo->accel = 0;
1076        }
1077}
1078
1079static int
1080sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1081{
1082        int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
1083
1084        if(maxyres > 32767) maxyres = 32767;
1085
1086        return maxyres;
1087}
1088
1089static void
1090sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1091{
1092        ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1093        ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1094        if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1095                if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1096                        ivideo->scrnpitchCRT1 <<= 1;
1097                }
1098        }
1099}
1100
1101static void
1102sisfb_set_pitch(struct sis_video_info *ivideo)
1103{
1104        bool isslavemode = false;
1105        unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1106        unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1107
1108        if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
1109
1110        /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1111        if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1112                outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1113                setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
1114        }
1115
1116        /* We must not set the pitch for CRT2 if bridge is in slave mode */
1117        if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1118                orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
1119                outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1120                setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1121        }
1122}
1123
1124static void
1125sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1126{
1127        ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1128
1129        switch(var->bits_per_pixel) {
1130        case 8:
1131                var->red.offset = var->green.offset = var->blue.offset = 0;
1132                var->red.length = var->green.length = var->blue.length = 6;
1133                break;
1134        case 16:
1135                var->red.offset = 11;
1136                var->red.length = 5;
1137                var->green.offset = 5;
1138                var->green.length = 6;
1139                var->blue.offset = 0;
1140                var->blue.length = 5;
1141                var->transp.offset = 0;
1142                var->transp.length = 0;
1143                break;
1144        case 32:
1145                var->red.offset = 16;
1146                var->red.length = 8;
1147                var->green.offset = 8;
1148                var->green.length = 8;
1149                var->blue.offset = 0;
1150                var->blue.length = 8;
1151                var->transp.offset = 24;
1152                var->transp.length = 8;
1153                break;
1154        }
1155}
1156
1157static int
1158sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1159{
1160        unsigned short modeno = ivideo->mode_no;
1161
1162        /* >=2.6.12's fbcon clears the screen anyway */
1163        modeno |= 0x80;
1164
1165        outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1166
1167        sisfb_pre_setmode(ivideo);
1168
1169        if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
1170                printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1171                return -EINVAL;
1172        }
1173
1174        outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1175
1176        sisfb_post_setmode(ivideo);
1177
1178        return 0;
1179}
1180
1181
1182static int
1183sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1184{
1185        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1186        unsigned int htotal = 0, vtotal = 0;
1187        unsigned int drate = 0, hrate = 0;
1188        int found_mode = 0, ret;
1189        int old_mode;
1190        u32 pixclock;
1191
1192        htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1193
1194        vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1195
1196        pixclock = var->pixclock;
1197
1198        if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1199                vtotal += var->yres;
1200                vtotal <<= 1;
1201        } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1202                vtotal += var->yres;
1203                vtotal <<= 2;
1204        } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1205                vtotal += var->yres;
1206                vtotal <<= 1;
1207        } else         vtotal += var->yres;
1208
1209        if(!(htotal) || !(vtotal)) {
1210                DPRINTK("sisfb: Invalid 'var' information\n");
1211                return -EINVAL;
1212        }
1213
1214        if(pixclock && htotal && vtotal) {
1215                drate = 1000000000 / pixclock;
1216                hrate = (drate * 1000) / htotal;
1217                ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1218        } else {
1219                ivideo->refresh_rate = 60;
1220        }
1221
1222        old_mode = ivideo->sisfb_mode_idx;
1223        ivideo->sisfb_mode_idx = 0;
1224
1225        while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1226               (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1227                if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1228                    (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1229                    (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1230                        ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1231                        found_mode = 1;
1232                        break;
1233                }
1234                ivideo->sisfb_mode_idx++;
1235        }
1236
1237        if(found_mode) {
1238                ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1239                                ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1240        } else {
1241                ivideo->sisfb_mode_idx = -1;
1242        }
1243
1244               if(ivideo->sisfb_mode_idx < 0) {
1245                printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1246                       var->yres, var->bits_per_pixel);
1247                ivideo->sisfb_mode_idx = old_mode;
1248                return -EINVAL;
1249        }
1250
1251        ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1252
1253        if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1254                ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1255                ivideo->refresh_rate = 60;
1256        }
1257
1258        if(isactive) {
1259                /* If acceleration to be used? Need to know
1260                 * before pre/post_set_mode()
1261                 */
1262                ivideo->accel = 0;
1263#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1264#ifdef STUPID_ACCELF_TEXT_SHIT
1265                if(var->accel_flags & FB_ACCELF_TEXT) {
1266                        info->flags &= ~FBINFO_HWACCEL_DISABLED;
1267                } else {
1268                        info->flags |= FBINFO_HWACCEL_DISABLED;
1269                }
1270#endif
1271                if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1272#else
1273                if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1274#endif
1275
1276                if((ret = sisfb_set_mode(ivideo, 1))) {
1277                        return ret;
1278                }
1279
1280                ivideo->video_bpp    = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1281                ivideo->video_width  = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1282                ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1283
1284                sisfb_calc_pitch(ivideo, var);
1285                sisfb_set_pitch(ivideo);
1286
1287                sisfb_set_vparms(ivideo);
1288
1289                ivideo->current_width = ivideo->video_width;
1290                ivideo->current_height = ivideo->video_height;
1291                ivideo->current_bpp = ivideo->video_bpp;
1292                ivideo->current_htotal = htotal;
1293                ivideo->current_vtotal = vtotal;
1294                ivideo->current_linelength = ivideo->video_linelength;
1295                ivideo->current_pixclock = var->pixclock;
1296                ivideo->current_refresh_rate = ivideo->refresh_rate;
1297                ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1298        }
1299
1300        return 0;
1301}
1302
1303static void
1304sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1305{
1306        outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1307
1308        outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1309        outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1310        outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1311        if(ivideo->sisvga_engine == SIS_315_VGA) {
1312                setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1313        }
1314}
1315
1316static void
1317sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1318{
1319        if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1320                orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1321                outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1322                outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1323                outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1324                if(ivideo->sisvga_engine == SIS_315_VGA) {
1325                        setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1326                }
1327        }
1328}
1329
1330static int
1331sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1332{
1333        if(var->xoffset > (var->xres_virtual - var->xres)) {
1334                return -EINVAL;
1335        }
1336        if(var->yoffset > (var->yres_virtual - var->yres)) {
1337                return -EINVAL;
1338        }
1339
1340        ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
1341
1342        /* calculate base bpp dep. */
1343        switch(var->bits_per_pixel) {
1344        case 32:
1345                break;
1346        case 16:
1347                ivideo->current_base >>= 1;
1348                break;
1349        case 8:
1350        default:
1351                ivideo->current_base >>= 2;
1352                break;
1353        }
1354
1355        ivideo->current_base += (ivideo->video_offset >> 2);
1356
1357        sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1358        sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1359
1360        return 0;
1361}
1362
1363static int
1364sisfb_open(struct fb_info *info, int user)
1365{
1366        return 0;
1367}
1368
1369static int
1370sisfb_release(struct fb_info *info, int user)
1371{
1372        return 0;
1373}
1374
1375static int
1376sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1377                unsigned transp, struct fb_info *info)
1378{
1379        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1380
1381        if(regno >= sisfb_get_cmap_len(&info->var))
1382                return 1;
1383
1384        switch(info->var.bits_per_pixel) {
1385        case 8:
1386                outSISREG(SISDACA, regno);
1387                outSISREG(SISDACD, (red >> 10));
1388                outSISREG(SISDACD, (green >> 10));
1389                outSISREG(SISDACD, (blue >> 10));
1390                if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1391                        outSISREG(SISDAC2A, regno);
1392                        outSISREG(SISDAC2D, (red >> 8));
1393                        outSISREG(SISDAC2D, (green >> 8));
1394                        outSISREG(SISDAC2D, (blue >> 8));
1395                }
1396                break;
1397        case 16:
1398                if (regno >= 16)
1399                        break;
1400
1401                ((u32 *)(info->pseudo_palette))[regno] =
1402                                (red & 0xf800)          |
1403                                ((green & 0xfc00) >> 5) |
1404                                ((blue & 0xf800) >> 11);
1405                break;
1406        case 32:
1407                if (regno >= 16)
1408                        break;
1409
1410                red >>= 8;
1411                green >>= 8;
1412                blue >>= 8;
1413                ((u32 *)(info->pseudo_palette))[regno] =
1414                                (red << 16) | (green << 8) | (blue);
1415                break;
1416        }
1417        return 0;
1418}
1419
1420static int
1421sisfb_set_par(struct fb_info *info)
1422{
1423        int err;
1424
1425        if((err = sisfb_do_set_var(&info->var, 1, info)))
1426                return err;
1427
1428        sisfb_get_fix(&info->fix, -1, info);
1429
1430        return 0;
1431}
1432
1433static int
1434sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1435{
1436        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1437        unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1438        unsigned int drate = 0, hrate = 0, maxyres;
1439        int found_mode = 0;
1440        int refresh_rate, search_idx, tidx;
1441        bool recalc_clock = false;
1442        u32 pixclock;
1443
1444        htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1445
1446        vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1447
1448        pixclock = var->pixclock;
1449
1450        if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1451                vtotal += var->yres;
1452                vtotal <<= 1;
1453        } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1454                vtotal += var->yres;
1455                vtotal <<= 2;
1456        } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1457                vtotal += var->yres;
1458                vtotal <<= 1;
1459        } else
1460                vtotal += var->yres;
1461
1462        if(!(htotal) || !(vtotal)) {
1463                SISFAIL("sisfb: no valid timing data");
1464        }
1465
1466        search_idx = 0;
1467        while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1468               (sisbios_mode[search_idx].xres <= var->xres) ) {
1469                if( (sisbios_mode[search_idx].xres == var->xres) &&
1470                    (sisbios_mode[search_idx].yres == var->yres) &&
1471                    (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1472                        if((tidx = sisfb_validate_mode(ivideo, search_idx,
1473                                                ivideo->currentvbflags)) > 0) {
1474                                found_mode = 1;
1475                                search_idx = tidx;
1476                                break;
1477                        }
1478                }
1479                search_idx++;
1480        }
1481
1482        if(!found_mode) {
1483                search_idx = 0;
1484                while(sisbios_mode[search_idx].mode_no[0] != 0) {
1485                   if( (var->xres <= sisbios_mode[search_idx].xres) &&
1486                       (var->yres <= sisbios_mode[search_idx].yres) &&
1487                       (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1488                        if((tidx = sisfb_validate_mode(ivideo,search_idx,
1489                                                ivideo->currentvbflags)) > 0) {
1490                                found_mode = 1;
1491                                search_idx = tidx;
1492                                break;
1493                        }
1494                   }
1495                   search_idx++;
1496                }
1497                if(found_mode) {
1498                        printk(KERN_DEBUG
1499                                "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1500                                var->xres, var->yres, var->bits_per_pixel,
1501                                sisbios_mode[search_idx].xres,
1502                                sisbios_mode[search_idx].yres,
1503                                var->bits_per_pixel);
1504                        var->xres = sisbios_mode[search_idx].xres;
1505                        var->yres = sisbios_mode[search_idx].yres;
1506                } else {
1507                        printk(KERN_ERR
1508                                "sisfb: Failed to find supported mode near %dx%dx%d\n",
1509                                var->xres, var->yres, var->bits_per_pixel);
1510                        return -EINVAL;
1511                }
1512        }
1513
1514        if( ((ivideo->vbflags2 & VB2_LVDS) ||
1515             ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1516            (var->bits_per_pixel == 8) ) {
1517                /* Slave modes on LVDS and 301B-DH */
1518                refresh_rate = 60;
1519                recalc_clock = true;
1520        } else if( (ivideo->current_htotal == htotal) &&
1521                   (ivideo->current_vtotal == vtotal) &&
1522                   (ivideo->current_pixclock == pixclock) ) {
1523                /* x=x & y=y & c=c -> assume depth change */
1524                drate = 1000000000 / pixclock;
1525                hrate = (drate * 1000) / htotal;
1526                refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1527        } else if( ( (ivideo->current_htotal != htotal) ||
1528                     (ivideo->current_vtotal != vtotal) ) &&
1529                   (ivideo->current_pixclock == var->pixclock) ) {
1530                /* x!=x | y!=y & c=c -> invalid pixclock */
1531                if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1532                        refresh_rate =
1533                                ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1534                } else if(ivideo->sisfb_parm_rate != -1) {
1535                        /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1536                        refresh_rate = ivideo->sisfb_parm_rate;
1537                } else {
1538                        refresh_rate = 60;
1539                }
1540                recalc_clock = true;
1541        } else if((pixclock) && (htotal) && (vtotal)) {
1542                drate = 1000000000 / pixclock;
1543                hrate = (drate * 1000) / htotal;
1544                refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1545        } else if(ivideo->current_refresh_rate) {
1546                refresh_rate = ivideo->current_refresh_rate;
1547                recalc_clock = true;
1548        } else {
1549                refresh_rate = 60;
1550                recalc_clock = true;
1551        }
1552
1553        myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1554
1555        /* Eventually recalculate timing and clock */
1556        if(recalc_clock) {
1557                if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1558                var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1559                                                sisbios_mode[search_idx].mode_no[ivideo->mni],
1560                                                myrateindex));
1561                sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1562                                        sisbios_mode[search_idx].mode_no[ivideo->mni],
1563                                        myrateindex, var);
1564                if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1565                        var->pixclock <<= 1;
1566                }
1567        }
1568
1569        if(ivideo->sisfb_thismonitor.datavalid) {
1570                if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1571                                myrateindex, refresh_rate)) {
1572                        printk(KERN_INFO
1573                                "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1574                }
1575        }
1576
1577        /* Adapt RGB settings */
1578        sisfb_bpp_to_var(ivideo, var);
1579
1580        /* Sanity check for offsets */
1581        if(var->xoffset < 0) var->xoffset = 0;
1582        if(var->yoffset < 0) var->yoffset = 0;
1583
1584        if(var->xres > var->xres_virtual)
1585                var->xres_virtual = var->xres;
1586
1587        if(ivideo->sisfb_ypan) {
1588                maxyres = sisfb_calc_maxyres(ivideo, var);
1589                if(ivideo->sisfb_max) {
1590                        var->yres_virtual = maxyres;
1591                } else {
1592                        if(var->yres_virtual > maxyres) {
1593                                var->yres_virtual = maxyres;
1594                        }
1595                }
1596                if(var->yres_virtual <= var->yres) {
1597                        var->yres_virtual = var->yres;
1598                }
1599        } else {
1600                if(var->yres != var->yres_virtual) {
1601                        var->yres_virtual = var->yres;
1602                }
1603                var->xoffset = 0;
1604                var->yoffset = 0;
1605        }
1606
1607        /* Truncate offsets to maximum if too high */
1608        if(var->xoffset > var->xres_virtual - var->xres) {
1609                var->xoffset = var->xres_virtual - var->xres - 1;
1610        }
1611
1612        if(var->yoffset > var->yres_virtual - var->yres) {
1613                var->yoffset = var->yres_virtual - var->yres - 1;
1614        }
1615
1616        /* Set everything else to 0 */
1617        var->red.msb_right =
1618                var->green.msb_right =
1619                var->blue.msb_right =
1620                var->transp.offset =
1621                var->transp.length =
1622                var->transp.msb_right = 0;
1623
1624        return 0;
1625}
1626
1627static int
1628sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1629{
1630        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1631        int err;
1632
1633        if(var->xoffset > (var->xres_virtual - var->xres))
1634                return -EINVAL;
1635
1636        if(var->yoffset > (var->yres_virtual - var->yres))
1637                return -EINVAL;
1638
1639        if(var->vmode & FB_VMODE_YWRAP)
1640                return -EINVAL;
1641
1642        if(var->xoffset + info->var.xres > info->var.xres_virtual ||
1643           var->yoffset + info->var.yres > info->var.yres_virtual)
1644                return -EINVAL;
1645
1646        if((err = sisfb_pan_var(ivideo, var)) < 0)
1647                return err;
1648
1649        info->var.xoffset = var->xoffset;
1650        info->var.yoffset = var->yoffset;
1651
1652        return 0;
1653}
1654
1655static int
1656sisfb_blank(int blank, struct fb_info *info)
1657{
1658        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1659
1660        return sisfb_myblank(ivideo, blank);
1661}
1662
1663/* ----------- FBDev related routines for all series ---------- */
1664
1665static int        sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1666                            unsigned long arg)
1667{
1668        struct sis_video_info        *ivideo = (struct sis_video_info *)info->par;
1669        struct sis_memreq        sismemreq;
1670        struct fb_vblank        sisvbblank;
1671        u32                        gpu32 = 0;
1672#ifndef __user
1673#define __user
1674#endif
1675        u32 __user                 *argp = (u32 __user *)arg;
1676
1677        switch(cmd) {
1678           case FBIO_ALLOC:
1679                if(!capable(CAP_SYS_RAWIO))
1680                        return -EPERM;
1681
1682                if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1683                        return -EFAULT;
1684
1685                sis_malloc(&sismemreq);
1686
1687                if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1688                        sis_free((u32)sismemreq.offset);
1689                        return -EFAULT;
1690                }
1691                break;
1692
1693           case FBIO_FREE:
1694                if(!capable(CAP_SYS_RAWIO))
1695                        return -EPERM;
1696
1697                if(get_user(gpu32, argp))
1698                        return -EFAULT;
1699
1700                sis_free(gpu32);
1701                break;
1702
1703           case FBIOGET_VBLANK:
1704                sisvbblank.count = 0;
1705                sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1706
1707                if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1708                        return -EFAULT;
1709
1710                break;
1711
1712           case SISFB_GET_INFO_SIZE:
1713                return put_user(sizeof(struct sisfb_info), argp);
1714
1715           case SISFB_GET_INFO_OLD:
1716                if(ivideo->warncount++ < 10)
1717                        printk(KERN_INFO
1718                                "sisfb: Deprecated ioctl call received - update your application!\n");
1719           case SISFB_GET_INFO:  /* For communication with X driver */
1720                ivideo->sisfb_infoblock.sisfb_id         = SISFB_ID;
1721                ivideo->sisfb_infoblock.sisfb_version    = VER_MAJOR;
1722                ivideo->sisfb_infoblock.sisfb_revision   = VER_MINOR;
1723                ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1724                ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1725                ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1726                ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1727                ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1728                if(ivideo->modechanged) {
1729                        ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1730                } else {
1731                        ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1732                }
1733                ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1734                ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1735                ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1736                ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1737                ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1738                ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1739                ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1740                ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1741                ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1742                ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1743                ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1744                ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1745                ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1746                ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1747                ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1748                ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1749                ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1750                ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1751                ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1752                ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1753                ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1754                ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1755                ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1756                ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1757                ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1758                ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1759                ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1760                ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1761
1762                if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1763                                                sizeof(ivideo->sisfb_infoblock)))
1764                        return -EFAULT;
1765
1766                break;
1767
1768           case SISFB_GET_VBRSTATUS_OLD:
1769                if(ivideo->warncount++ < 10)
1770                        printk(KERN_INFO
1771                                "sisfb: Deprecated ioctl call received - update your application!\n");
1772           case SISFB_GET_VBRSTATUS:
1773                if(sisfb_CheckVBRetrace(ivideo))
1774                        return put_user((u32)1, argp);
1775                else
1776                        return put_user((u32)0, argp);
1777
1778           case SISFB_GET_AUTOMAXIMIZE_OLD:
1779                if(ivideo->warncount++ < 10)
1780                        printk(KERN_INFO
1781                                "sisfb: Deprecated ioctl call received - update your application!\n");
1782           case SISFB_GET_AUTOMAXIMIZE:
1783                if(ivideo->sisfb_max)
1784                        return put_user((u32)1, argp);
1785                else
1786                        return put_user((u32)0, argp);
1787
1788           case SISFB_SET_AUTOMAXIMIZE_OLD:
1789                if(ivideo->warncount++ < 10)
1790                        printk(KERN_INFO
1791                                "sisfb: Deprecated ioctl call received - update your application!\n");
1792           case SISFB_SET_AUTOMAXIMIZE:
1793                if(get_user(gpu32, argp))
1794                        return -EFAULT;
1795
1796                ivideo->sisfb_max = (gpu32) ? 1 : 0;
1797                break;
1798
1799           case SISFB_SET_TVPOSOFFSET:
1800                if(get_user(gpu32, argp))
1801                        return -EFAULT;
1802
1803                sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1804                sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1805                break;
1806
1807           case SISFB_GET_TVPOSOFFSET:
1808                return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1809                                                        argp);
1810
1811           case SISFB_COMMAND:
1812                if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1813                                                        sizeof(struct sisfb_cmd)))
1814                        return -EFAULT;
1815
1816                sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1817
1818                if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1819                                                        sizeof(struct sisfb_cmd)))
1820                        return -EFAULT;
1821
1822                break;
1823
1824           case SISFB_SET_LOCK:
1825                if(get_user(gpu32, argp))
1826                        return -EFAULT;
1827
1828                ivideo->sisfblocked = (gpu32) ? 1 : 0;
1829                break;
1830
1831           default:
1832#ifdef SIS_NEW_CONFIG_COMPAT
1833                return -ENOIOCTLCMD;
1834#else
1835                return -EINVAL;
1836#endif
1837        }
1838        return 0;
1839}
1840
1841static int
1842sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1843{
1844        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1845
1846        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1847
1848        strcpy(fix->id, ivideo->myid);
1849
1850        fix->smem_start  = ivideo->video_base + ivideo->video_offset;
1851        fix->smem_len    = ivideo->sisfb_mem;
1852        fix->type        = FB_TYPE_PACKED_PIXELS;
1853        fix->type_aux    = 0;
1854        fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1855        fix->xpanstep    = 1;
1856        fix->ypanstep          = (ivideo->sisfb_ypan) ? 1 : 0;
1857        fix->ywrapstep   = 0;
1858        fix->line_length = ivideo->video_linelength;
1859        fix->mmio_start  = ivideo->mmio_base;
1860        fix->mmio_len    = ivideo->mmio_size;
1861        if(ivideo->sisvga_engine == SIS_300_VGA) {
1862                fix->accel = FB_ACCEL_SIS_GLAMOUR;
1863        } else if((ivideo->chip == SIS_330) ||
1864                  (ivideo->chip == SIS_760) ||
1865                  (ivideo->chip == SIS_761)) {
1866                fix->accel = FB_ACCEL_SIS_XABRE;
1867        } else if(ivideo->chip == XGI_20) {
1868                fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1869        } else if(ivideo->chip >= XGI_40) {
1870                fix->accel = FB_ACCEL_XGI_VOLARI_V;
1871        } else {
1872                fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1873        }
1874
1875        return 0;
1876}
1877
1878/* ----------------  fb_ops structures ----------------- */
1879
1880static struct fb_ops sisfb_ops = {
1881        .owner                = THIS_MODULE,
1882        .fb_open        = sisfb_open,
1883        .fb_release        = sisfb_release,
1884        .fb_check_var        = sisfb_check_var,
1885        .fb_set_par        = sisfb_set_par,
1886        .fb_setcolreg        = sisfb_setcolreg,
1887        .fb_pan_display        = sisfb_pan_display,
1888        .fb_blank        = sisfb_blank,
1889        .fb_fillrect        = fbcon_sis_fillrect,
1890        .fb_copyarea        = fbcon_sis_copyarea,
1891        .fb_imageblit        = cfb_imageblit,
1892#ifdef CONFIG_FB_SOFT_CURSOR
1893        .fb_cursor        = soft_cursor,
1894#endif
1895        .fb_sync        = fbcon_sis_sync,
1896#ifdef SIS_NEW_CONFIG_COMPAT
1897        .fb_compat_ioctl= sisfb_ioctl,
1898#endif
1899        .fb_ioctl        = sisfb_ioctl
1900};
1901
1902/* ---------------- Chip generation dependent routines ---------------- */
1903
1904static struct pci_dev * __devinit
1905sisfb_get_northbridge(int basechipid)
1906{
1907        struct pci_dev *pdev = NULL;
1908        int nbridgenum, nbridgeidx, i;
1909        static const unsigned short nbridgeids[] = {
1910                PCI_DEVICE_ID_SI_540,        /* for SiS 540 VGA */
1911                PCI_DEVICE_ID_SI_630,        /* for SiS 630/730 VGA */
1912                PCI_DEVICE_ID_SI_730,
1913                PCI_DEVICE_ID_SI_550,   /* for SiS 550 VGA */
1914                PCI_DEVICE_ID_SI_650,   /* for SiS 650/651/740 VGA */
1915                PCI_DEVICE_ID_SI_651,
1916                PCI_DEVICE_ID_SI_740,
1917                PCI_DEVICE_ID_SI_661,        /* for SiS 661/741/660/760/761 VGA */
1918                PCI_DEVICE_ID_SI_741,
1919                PCI_DEVICE_ID_SI_660,
1920                PCI_DEVICE_ID_SI_760,
1921                PCI_DEVICE_ID_SI_761
1922        };
1923
1924        switch(basechipid) {
1925#ifdef CONFIG_FB_SIS_300
1926        case SIS_540:        nbridgeidx = 0; nbridgenum = 1; break;
1927        case SIS_630:        nbridgeidx = 1; nbridgenum = 2; break;
1928#endif
1929#ifdef CONFIG_FB_SIS_315
1930        case SIS_550:   nbridgeidx = 3; nbridgenum = 1; break;
1931        case SIS_650:        nbridgeidx = 4; nbridgenum = 3; break;
1932        case SIS_660:        nbridgeidx = 7; nbridgenum = 5; break;
1933#endif
1934        default:        return NULL;
1935        }
1936        for(i = 0; i < nbridgenum; i++) {
1937                if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
1938                                nbridgeids[nbridgeidx+i], NULL)))
1939                        break;
1940        }
1941        return pdev;
1942}
1943
1944static int __devinit
1945sisfb_get_dram_size(struct sis_video_info *ivideo)
1946{
1947#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1948        u8 reg;
1949#endif
1950
1951        ivideo->video_size = 0;
1952        ivideo->UMAsize = ivideo->LFBsize = 0;
1953
1954        switch(ivideo->chip) {
1955#ifdef CONFIG_FB_SIS_300
1956        case SIS_300:
1957                inSISIDXREG(SISSR, 0x14, reg);
1958                ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1959                break;
1960        case SIS_540:
1961        case SIS_630:
1962        case SIS_730:
1963                if(!ivideo->nbridge)
1964                        return -1;
1965                pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
1966                ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1967                break;
1968#endif
1969#ifdef CONFIG_FB_SIS_315
1970        case SIS_315H:
1971        case SIS_315PRO:
1972        case SIS_315:
1973                inSISIDXREG(SISSR, 0x14, reg);
1974                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1975                switch((reg >> 2) & 0x03) {
1976                case 0x01:
1977                case 0x03:
1978                        ivideo->video_size <<= 1;
1979                        break;
1980                case 0x02:
1981                        ivideo->video_size += (ivideo->video_size/2);
1982                }
1983                break;
1984        case SIS_330:
1985                inSISIDXREG(SISSR, 0x14, reg);
1986                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1987                if(reg & 0x0c) ivideo->video_size <<= 1;
1988                break;
1989        case SIS_550:
1990        case SIS_650:
1991        case SIS_740:
1992                inSISIDXREG(SISSR, 0x14, reg);
1993                ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
1994                break;
1995        case SIS_661:
1996        case SIS_741:
1997                inSISIDXREG(SISCR, 0x79, reg);
1998                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1999                break;
2000        case SIS_660:
2001        case SIS_760:
2002        case SIS_761:
2003                inSISIDXREG(SISCR, 0x79, reg);
2004                reg = (reg & 0xf0) >> 4;
2005                if(reg)        {
2006                        ivideo->video_size = (1 << reg) << 20;
2007                        ivideo->UMAsize = ivideo->video_size;
2008                }
2009                inSISIDXREG(SISCR, 0x78, reg);
2010                reg &= 0x30;
2011                if(reg) {
2012                        if(reg == 0x10) {
2013                                ivideo->LFBsize = (32 << 20);
2014                        } else {
2015                                ivideo->LFBsize = (64 << 20);
2016                        }
2017                        ivideo->video_size += ivideo->LFBsize;
2018                }
2019                break;
2020        case SIS_340:
2021        case XGI_20:
2022        case XGI_40:
2023                inSISIDXREG(SISSR, 0x14, reg);
2024                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2025                if(ivideo->chip != XGI_20) {
2026                        reg = (reg & 0x0c) >> 2;
2027                        if(ivideo->revision_id == 2) {
2028                                if(reg & 0x01) reg = 0x02;
2029                                else               reg = 0x00;
2030                        }
2031                        if(reg == 0x02)                ivideo->video_size <<= 1;
2032                        else if(reg == 0x03)        ivideo->video_size <<= 2;
2033                }
2034                break;
2035#endif
2036        default:
2037                return -1;
2038        }
2039        return 0;
2040}
2041
2042/* -------------- video bridge device detection --------------- */
2043
2044static void __devinit
2045sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2046{
2047        u8 cr32, temp;
2048
2049        /* No CRT2 on XGI Z7 */
2050        if(ivideo->chip == XGI_20) {
2051                ivideo->sisfb_crt1off = 0;
2052                return;
2053        }
2054
2055#ifdef CONFIG_FB_SIS_300
2056        if(ivideo->sisvga_engine == SIS_300_VGA) {
2057                inSISIDXREG(SISSR, 0x17, temp);
2058                if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2059                        /* PAL/NTSC is stored on SR16 on such machines */
2060                        if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2061                                inSISIDXREG(SISSR, 0x16, temp);
2062                                if(temp & 0x20)
2063                                        ivideo->vbflags |= TV_PAL;
2064                                else
2065                                        ivideo->vbflags |= TV_NTSC;
2066                        }
2067                }
2068        }
2069#endif
2070
2071        inSISIDXREG(SISCR, 0x32, cr32);
2072
2073        if(cr32 & SIS_CRT1) {
2074                ivideo->sisfb_crt1off = 0;
2075        } else {
2076                ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2077        }
2078
2079        ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2080
2081        if(cr32 & SIS_VB_TV)   ivideo->vbflags |= CRT2_TV;
2082        if(cr32 & SIS_VB_LCD)  ivideo->vbflags |= CRT2_LCD;
2083        if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2084
2085        /* Check given parms for hardware compatibility.
2086         * (Cannot do this in the search_xx routines since we don't
2087         * know what hardware we are running on then)
2088         */
2089
2090        if(ivideo->chip != SIS_550) {
2091           ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2092        }
2093
2094        if(ivideo->sisfb_tvplug != -1) {
2095           if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2096               (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2097              if(ivideo->sisfb_tvplug & TV_YPBPR) {
2098                 ivideo->sisfb_tvplug = -1;
2099                 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2100              }
2101           }
2102        }
2103        if(ivideo->sisfb_tvplug != -1) {
2104           if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2105               (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2106              if(ivideo->sisfb_tvplug & TV_HIVISION) {
2107                 ivideo->sisfb_tvplug = -1;
2108                 printk(KERN_ERR "sisfb: HiVision not supported\n");
2109              }
2110           }
2111        }
2112        if(ivideo->sisfb_tvstd != -1) {
2113           if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2114               (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2115                        (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2116              if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2117                 ivideo->sisfb_tvstd = -1;
2118                 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2119              }
2120           }
2121        }
2122
2123        /* Detect/set TV plug & type */
2124        if(ivideo->sisfb_tvplug != -1) {
2125                ivideo->vbflags |= ivideo->sisfb_tvplug;
2126        } else {
2127                if(cr32 & SIS_VB_YPBPR)              ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2128                else if(cr32 & SIS_VB_HIVISION)  ivideo->vbflags |= TV_HIVISION;
2129                else if(cr32 & SIS_VB_SCART)     ivideo->vbflags |= TV_SCART;
2130                else {
2131                        if(cr32 & SIS_VB_SVIDEO)    ivideo->vbflags |= TV_SVIDEO;
2132                        if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2133                }
2134        }
2135
2136        if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2137            if(ivideo->sisfb_tvstd != -1) {
2138               ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2139               ivideo->vbflags |= ivideo->sisfb_tvstd;
2140            }
2141            if(ivideo->vbflags & TV_SCART) {
2142               ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2143               ivideo->vbflags |= TV_PAL;
2144            }
2145            if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2146                if(ivideo->sisvga_engine == SIS_300_VGA) {
2147                        inSISIDXREG(SISSR, 0x38, temp);
2148                        if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2149                        else                ivideo->vbflags |= TV_NTSC;
2150                } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2151                        inSISIDXREG(SISSR, 0x38, temp);
2152                        if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2153                        else                ivideo->vbflags |= TV_NTSC;
2154                } else {
2155                        inSISIDXREG(SISCR, 0x79, temp);
2156                        if(temp & 0x20)        ivideo->vbflags |= TV_PAL;
2157                        else                ivideo->vbflags |= TV_NTSC;
2158                }
2159            }
2160        }
2161
2162        /* Copy forceCRT1 option to CRT1off if option is given */
2163        if(ivideo->sisfb_forcecrt1 != -1) {
2164           ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2165        }
2166}
2167
2168/* ------------------ Sensing routines ------------------ */
2169
2170static bool __devinit
2171sisfb_test_DDC1(struct sis_video_info *ivideo)
2172{
2173    unsigned short old;
2174    int count = 48;
2175
2176    old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2177    do {
2178        if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2179    } while(count--);
2180    return (count != -1);
2181}
2182
2183static void __devinit
2184sisfb_sense_crt1(struct sis_video_info *ivideo)
2185{
2186    bool mustwait = false;
2187    u8  sr1F, cr17;
2188#ifdef CONFIG_FB_SIS_315
2189    u8  cr63=0;
2190#endif
2191    u16 temp = 0xffff;
2192    int i;
2193
2194    inSISIDXREG(SISSR,0x1F,sr1F);
2195    orSISIDXREG(SISSR,0x1F,0x04);
2196    andSISIDXREG(SISSR,0x1F,0x3F);
2197    if(sr1F & 0xc0) mustwait = true;
2198
2199#ifdef CONFIG_FB_SIS_315
2200    if(ivideo->sisvga_engine == SIS_315_VGA) {
2201       inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2202       cr63 &= 0x40;
2203       andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2204    }
2205#endif
2206
2207    inSISIDXREG(SISCR,0x17,cr17);
2208    cr17 &= 0x80;
2209    if(!cr17) {
2210       orSISIDXREG(SISCR,0x17,0x80);
2211       mustwait = true;
2212       outSISIDXREG(SISSR, 0x00, 0x01);
2213       outSISIDXREG(SISSR, 0x00, 0x03);
2214    }
2215
2216    if(mustwait) {
2217       for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2218    }
2219
2220#ifdef CONFIG_FB_SIS_315
2221    if(ivideo->chip >= SIS_330) {
2222       andSISIDXREG(SISCR,0x32,~0x20);
2223       if(ivideo->chip >= SIS_340) {
2224          outSISIDXREG(SISCR, 0x57, 0x4a);
2225       } else {
2226          outSISIDXREG(SISCR, 0x57, 0x5f);
2227       }
2228       orSISIDXREG(SISCR, 0x53, 0x02);
2229       while((inSISREG(SISINPSTAT)) & 0x01)    break;
2230       while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2231       if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2232       andSISIDXREG(SISCR, 0x53, 0xfd);
2233       andSISIDXREG(SISCR, 0x57, 0x00);
2234    }
2235#endif
2236
2237    if(temp == 0xffff) {
2238       i = 3;
2239       do {
2240          temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2241                ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2242       } while(((temp == 0) || (temp == 0xffff)) && i--);
2243
2244       if((temp == 0) || (temp == 0xffff)) {
2245          if(sisfb_test_DDC1(ivideo)) temp = 1;
2246       }
2247    }
2248
2249    if((temp) && (temp != 0xffff)) {
2250       orSISIDXREG(SISCR,0x32,0x20);
2251    }
2252
2253#ifdef CONFIG_FB_SIS_315
2254    if(ivideo->sisvga_engine == SIS_315_VGA) {
2255       setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2256    }
2257#endif
2258
2259    setSISIDXREG(SISCR,0x17,0x7F,cr17);
2260
2261    outSISIDXREG(SISSR,0x1F,sr1F);
2262}
2263
2264/* Determine and detect attached devices on SiS30x */
2265static void __devinit
2266SiS_SenseLCD(struct sis_video_info *ivideo)
2267{
2268        unsigned char buffer[256];
2269        unsigned short temp, realcrtno, i;
2270        u8 reg, cr37 = 0, paneltype = 0;
2271        u16 xres, yres;
2272
2273        ivideo->SiS_Pr.PanelSelfDetected = false;
2274
2275        /* LCD detection only for TMDS bridges */
2276        if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2277                return;
2278        if(ivideo->vbflags2 & VB2_30xBDH)
2279                return;
2280
2281        /* If LCD already set up by BIOS, skip it */
2282        inSISIDXREG(SISCR, 0x32, reg);
2283        if(reg & 0x08)
2284                return;
2285
2286        realcrtno = 1;
2287        if(ivideo->SiS_Pr.DDCPortMixup)
2288                realcrtno = 0;
2289
2290        /* Check DDC capabilities */
2291        temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2292                                realcrtno, 0, &buffer[0], ivideo->vbflags2);
2293
2294        if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2295                return;
2296
2297        /* Read DDC data */
2298        i = 3;  /* Number of retrys */
2299        do {
2300                temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2301                                ivideo->sisvga_engine, realcrtno, 1,
2302                                &buffer[0], ivideo->vbflags2);
2303        } while((temp) && i--);
2304
2305        if(temp)
2306                return;
2307
2308        /* No digital device */
2309        if(!(buffer[0x14] & 0x80))
2310                return;
2311
2312        /* First detailed timing preferred timing? */
2313        if(!(buffer[0x18] & 0x02))
2314                return;
2315
2316        xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2317        yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2318
2319        switch(xres) {
2320                case 1024:
2321                        if(yres == 768)
2322                                paneltype = 0x02;
2323                        break;
2324                case 1280:
2325                        if(yres == 1024)
2326                                paneltype = 0x03;
2327                        break;
2328                case 1600:
2329                        if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2330                                paneltype = 0x0b;
2331                        break;
2332        }
2333
2334        if(!paneltype)
2335                return;
2336
2337        if(buffer[0x23])
2338                cr37 |= 0x10;
2339
2340        if((buffer[0x47] & 0x18) == 0x18)
2341                cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2342        else
2343                cr37 |= 0xc0;
2344
2345        outSISIDXREG(SISCR, 0x36, paneltype);
2346        cr37 &= 0xf1;
2347        setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2348        orSISIDXREG(SISCR, 0x32, 0x08);
2349
2350        ivideo->SiS_Pr.PanelSelfDetected = true;
2351}
2352
2353static int __devinit
2354SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2355{
2356    int temp, mytest, result, i, j;
2357
2358    for(j = 0; j < 10; j++) {
2359       result = 0;
2360       for(i = 0; i < 3; i++) {
2361          mytest = test;
2362          outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2363          temp = (type >> 8) | (mytest & 0x00ff);
2364          setSISIDXREG(SISPART4,0x10,0xe0,temp);
2365          SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2366          mytest >>= 8;
2367          mytest &= 0x7f;
2368          inSISIDXREG(SISPART4,0x03,temp);
2369          temp ^= 0x0e;
2370          temp &= mytest;
2371          if(temp == mytest) result++;
2372#if 1
2373          outSISIDXREG(SISPART4,0x11,0x00);
2374          andSISIDXREG(SISPART4,0x10,0xe0);
2375          SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2376#endif
2377       }
2378       if((result == 0) || (result >= 2)) break;
2379    }
2380    return result;
2381}
2382
2383static void __devinit
2384SiS_Sense30x(struct sis_video_info *ivideo)
2385{
2386    u8  backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2387    u16 svhs=0, svhs_c=0;
2388    u16 cvbs=0, cvbs_c=0;
2389    u16 vga2=0, vga2_c=0;
2390    int myflag, result;
2391    char stdstr[] = "sisfb: Detected";
2392    char tvstr[]  = "TV connected to";
2393
2394    if(ivideo->vbflags2 & VB2_301) {
2395       svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2396       inSISIDXREG(SISPART4,0x01,myflag);
2397       if(myflag & 0x04) {
2398          svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2399       }
2400    } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2401       svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2402    } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2403       svhs = 0x0200; cvbs = 0x0100;
2404    } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2405       svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2406    } else
2407       return;
2408
2409    vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2410    if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2411       svhs_c = 0x0408; cvbs_c = 0x0808;
2412    }
2413
2414    biosflag = 2;
2415    if(ivideo->haveXGIROM) {
2416       biosflag = ivideo->bios_abase[0x58] & 0x03;
2417    } else if(ivideo->newrom) {
2418       if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2419    } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2420       if(ivideo->bios_abase) {
2421          biosflag = ivideo->bios_abase[0xfe] & 0x03;
2422       }
2423    }
2424
2425    if(ivideo->chip == SIS_300) {
2426       inSISIDXREG(SISSR,0x3b,myflag);
2427       if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2428    }
2429
2430    if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2431       vga2 = vga2_c = 0;
2432    }
2433
2434    inSISIDXREG(SISSR,0x1e,backupSR_1e);
2435    orSISIDXREG(SISSR,0x1e,0x20);
2436
2437    inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2438    if(ivideo->vbflags2 & VB2_30xC) {
2439       setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2440    } else {
2441       orSISIDXREG(SISPART4,0x0d,0x04);
2442    }
2443    SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2444
2445    inSISIDXREG(SISPART2,0x00,backupP2_00);
2446    outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2447
2448    inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2449    if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2450       outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2451    }
2452
2453    if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2454       SISDoSense(ivideo, 0, 0);
2455    }
2456
2457    andSISIDXREG(SISCR, 0x32, ~0x14);
2458
2459    if(vga2_c || vga2) {
2460       if(SISDoSense(ivideo, vga2, vga2_c)) {
2461          if(biosflag & 0x01) {
2462             printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2463             orSISIDXREG(SISCR, 0x32, 0x04);
2464          } else {
2465             printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2466             orSISIDXREG(SISCR, 0x32, 0x10);
2467          }
2468       }
2469    }
2470
2471    andSISIDXREG(SISCR, 0x32, 0x3f);
2472
2473    if(ivideo->vbflags2 & VB2_30xCLV) {
2474       orSISIDXREG(SISPART4,0x0d,0x04);
2475    }
2476
2477    if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2478       outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2479       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2480       if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2481          if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2482             printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2483             orSISIDXREG(SISCR,0x32,0x80);
2484          }
2485       }
2486       outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2487    }
2488
2489    andSISIDXREG(SISCR, 0x32, ~0x03);
2490
2491    if(!(ivideo->vbflags & TV_YPBPR)) {
2492       if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2493          printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2494          orSISIDXREG(SISCR, 0x32, 0x02);
2495       }
2496       if((biosflag & 0x02) || (!result)) {
2497          if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2498             printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2499             orSISIDXREG(SISCR, 0x32, 0x01);
2500          }
2501       }
2502    }
2503
2504    SISDoSense(ivideo, 0, 0);
2505
2506    outSISIDXREG(SISPART2,0x00,backupP2_00);
2507    outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2508    outSISIDXREG(SISSR,0x1e,backupSR_1e);
2509
2510    if(ivideo->vbflags2 & VB2_30xCLV) {
2511       inSISIDXREG(SISPART2,0x00,biosflag);
2512       if(biosflag & 0x20) {
2513          for(myflag = 2; myflag > 0; myflag--) {
2514             biosflag ^= 0x20;
2515             outSISIDXREG(SISPART2,0x00,biosflag);
2516          }
2517       }
2518    }
2519
2520    outSISIDXREG(SISPART2,0x00,backupP2_00);
2521}
2522
2523/* Determine and detect attached TV's on Chrontel */
2524static void __devinit
2525SiS_SenseCh(struct sis_video_info *ivideo)
2526{
2527#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2528    u8 temp1, temp2;
2529    char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2530#endif
2531#ifdef CONFIG_FB_SIS_300
2532    unsigned char test[3];
2533    int i;
2534#endif
2535
2536    if(ivideo->chip < SIS_315H) {
2537
2538#ifdef CONFIG_FB_SIS_300
2539       ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1;                /* Chrontel 700x */
2540       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c);        /* Set general purpose IO for Chrontel communication */
2541       SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2542       temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2543       /* See Chrontel TB31 for explanation */
2544       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2545       if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2546          SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2547          SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2548       }
2549       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2550       if(temp2 != temp1) temp1 = temp2;
2551
2552       if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2553           /* Read power status */
2554           temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2555           if((temp1 & 0x03) != 0x03) {
2556                /* Power all outputs */
2557                SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2558                SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2559           }
2560           /* Sense connected TV devices */
2561           for(i = 0; i < 3; i++) {
2562               SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2563               SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2564               SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2565               SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2566               temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2567               if(!(temp1 & 0x08))       test[i] = 0x02;
2568               else if(!(temp1 & 0x02))  test[i] = 0x01;
2569               else                      test[i] = 0;
2570               SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2571           }
2572
2573           if(test[0] == test[1])      temp1 = test[0];
2574           else if(test[0] == test[2]) temp1 = test[0];
2575           else if(test[1] == test[2]) temp1 = test[1];
2576           else {
2577                printk(KERN_INFO
2578                        "sisfb: TV detection unreliable - test results varied\n");
2579                temp1 = test[2];
2580           }
2581           if(temp1 == 0x02) {
2582                printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2583                ivideo->vbflags |= TV_SVIDEO;
2584                orSISIDXREG(SISCR, 0x32, 0x02);
2585                andSISIDXREG(SISCR, 0x32, ~0x05);
2586           } else if (temp1 == 0x01) {
2587                printk(KERN_INFO "%s CVBS output\n", stdstr);
2588                ivideo->vbflags |= TV_AVIDEO;
2589                orSISIDXREG(SISCR, 0x32, 0x01);
2590                andSISIDXREG(SISCR, 0x32, ~0x06);
2591           } else {
2592                SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2593                andSISIDXREG(SISCR, 0x32, ~0x07);
2594           }
2595       } else if(temp1 == 0) {
2596          SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2597          andSISIDXREG(SISCR, 0x32, ~0x07);
2598       }
2599       /* Set general purpose IO for Chrontel communication */
2600       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2601#endif
2602
2603    } else {
2604
2605#ifdef CONFIG_FB_SIS_315
2606        ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2;                /* Chrontel 7019 */
2607        temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2608        SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2609        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2610        temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2611        temp2 |= 0x01;
2612        SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2613        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2614        temp2 ^= 0x01;
2615        SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2616        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2617        temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2618        SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2619        temp1 = 0;
2620        if(temp2 & 0x02) temp1 |= 0x01;
2621        if(temp2 & 0x10) temp1 |= 0x01;
2622        if(temp2 & 0x04) temp1 |= 0x02;
2623        if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2624        switch(temp1) {
2625        case 0x01:
2626             printk(KERN_INFO "%s CVBS output\n", stdstr);
2627             ivideo->vbflags |= TV_AVIDEO;
2628             orSISIDXREG(SISCR, 0x32, 0x01);
2629             andSISIDXREG(SISCR, 0x32, ~0x06);
2630             break;
2631        case 0x02:
2632             printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2633             ivideo->vbflags |= TV_SVIDEO;
2634             orSISIDXREG(SISCR, 0x32, 0x02);
2635             andSISIDXREG(SISCR, 0x32, ~0x05);
2636             break;
2637        case 0x04:
2638             printk(KERN_INFO "%s SCART output\n", stdstr);
2639             orSISIDXREG(SISCR, 0x32, 0x04);
2640             andSISIDXREG(SISCR, 0x32, ~0x03);
2641             break;
2642        default:
2643             andSISIDXREG(SISCR, 0x32, ~0x07);
2644        }
2645#endif
2646    }
2647}
2648
2649static void __devinit
2650sisfb_get_VB_type(struct sis_video_info *ivideo)
2651{
2652        char stdstr[]    = "sisfb: Detected";
2653        char bridgestr[] = "video bridge";
2654        u8 vb_chipid;
2655        u8 reg;
2656
2657        /* No CRT2 on XGI Z7 */
2658        if(ivideo->chip == XGI_20)
2659                return;
2660
2661        inSISIDXREG(SISPART4, 0x00, vb_chipid);
2662        switch(vb_chipid) {
2663        case 0x01:
2664                inSISIDXREG(SISPART4, 0x01, reg);
2665                if(reg < 0xb0) {
2666                        ivideo->vbflags |= VB_301;        /* Deprecated */
2667                        ivideo->vbflags2 |= VB2_301;
2668                        printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2669                } else if(reg < 0xc0) {
2670                        ivideo->vbflags |= VB_301B;        /* Deprecated */
2671                        ivideo->vbflags2 |= VB2_301B;
2672                        inSISIDXREG(SISPART4,0x23,reg);
2673                        if(!(reg & 0x02)) {
2674                           ivideo->vbflags |= VB_30xBDH;        /* Deprecated */
2675                           ivideo->vbflags2 |= VB2_30xBDH;
2676                           printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2677                        } else {
2678                           printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2679                        }
2680                } else if(reg < 0xd0) {
2681                        ivideo->vbflags |= VB_301C;        /* Deprecated */
2682                        ivideo->vbflags2 |= VB2_301C;
2683                        printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2684                } else if(reg < 0xe0) {
2685                        ivideo->vbflags |= VB_301LV;        /* Deprecated */
2686                        ivideo->vbflags2 |= VB2_301LV;
2687                        printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2688                } else if(reg <= 0xe1) {
2689                        inSISIDXREG(SISPART4,0x39,reg);
2690                        if(reg == 0xff) {
2691                           ivideo->vbflags |= VB_302LV;        /* Deprecated */
2692                           ivideo->vbflags2 |= VB2_302LV;
2693                           printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2694                        } else {
2695                           ivideo->vbflags |= VB_301C;        /* Deprecated */
2696                           ivideo->vbflags2 |= VB2_301C;
2697                           printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2698#if 0
2699                           ivideo->vbflags |= VB_302ELV;        /* Deprecated */
2700                           ivideo->vbflags2 |= VB2_302ELV;
2701                           printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2702#endif
2703                        }
2704                }
2705                break;
2706        case 0x02:
2707                ivideo->vbflags |= VB_302B;        /* Deprecated */
2708                ivideo->vbflags2 |= VB2_302B;
2709                printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2710                break;
2711        }
2712
2713        if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2714                inSISIDXREG(SISCR, 0x37, reg);
2715                reg &= SIS_EXTERNAL_CHIP_MASK;
2716                reg >>= 1;
2717                if(ivideo->sisvga_engine == SIS_300_VGA) {
2718#ifdef CONFIG_FB_SIS_300
2719                        switch(reg) {
2720                           case SIS_EXTERNAL_CHIP_LVDS:
2721                                ivideo->vbflags |= VB_LVDS;        /* Deprecated */
2722                                ivideo->vbflags2 |= VB2_LVDS;
2723                                break;
2724                           case SIS_EXTERNAL_CHIP_TRUMPION:
2725                                ivideo->vbflags |= (VB_LVDS | VB_TRUMPION);        /* Deprecated */
2726                                ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2727                                break;
2728                           case SIS_EXTERNAL_CHIP_CHRONTEL:
2729                                ivideo->vbflags |= VB_CHRONTEL;        /* Deprecated */
2730                                ivideo->vbflags2 |= VB2_CHRONTEL;
2731                                break;
2732                           case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2733                                ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);        /* Deprecated */
2734                                ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2735                                break;
2736                        }
2737                        if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2738#endif
2739                } else if(ivideo->chip < SIS_661) {
2740#ifdef CONFIG_FB_SIS_315
2741                        switch (reg) {
2742                           case SIS310_EXTERNAL_CHIP_LVDS:
2743                                ivideo->vbflags |= VB_LVDS;        /* Deprecated */
2744                                ivideo->vbflags2 |= VB2_LVDS;
2745                                break;
2746                           case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2747                                ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);        /* Deprecated */
2748                                ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2749                                break;
2750                        }
2751                        if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2752#endif
2753                } else if(ivideo->chip >= SIS_661) {
2754#ifdef CONFIG_FB_SIS_315
2755                        inSISIDXREG(SISCR, 0x38, reg);
2756                        reg >>= 5;
2757                        switch(reg) {
2758                           case 0x02:
2759                                ivideo->vbflags |= VB_LVDS;        /* Deprecated */
2760                                ivideo->vbflags2 |= VB2_LVDS;
2761                                break;
2762                           case 0x03:
2763                                ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);        /* Deprecated */
2764                                ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2765                                break;
2766                           case 0x04:
2767                                ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);        /* Deprecated */
2768                                ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2769                                break;
2770                        }
2771                        if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2772#endif
2773                }
2774                if(ivideo->vbflags2 & VB2_LVDS) {
2775                   printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2776                }
2777                if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2778                   printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2779                }
2780                if(ivideo->vbflags2 & VB2_CHRONTEL) {
2781                   printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2782                }
2783                if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2784                   printk(KERN_INFO "%s Conexant external device\n", stdstr);
2785                }
2786        }
2787
2788        if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2789                SiS_SenseLCD(ivideo);
2790                SiS_Sense30x(ivideo);
2791        } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2792                SiS_SenseCh(ivideo);
2793        }
2794}
2795
2796/* ---------- Engine initialization routines ------------ */
2797
2798static void
2799sisfb_engine_init(struct sis_video_info *ivideo)
2800{
2801
2802        /* Initialize command queue (we use MMIO only) */
2803
2804        /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2805
2806        ivideo->caps &= ~(TURBO_QUEUE_CAP    |
2807                          MMIO_CMD_QUEUE_CAP |
2808                          VM_CMD_QUEUE_CAP   |
2809                          AGP_CMD_QUEUE_CAP);
2810
2811#ifdef CONFIG_FB_SIS_300
2812        if(ivideo->sisvga_engine == SIS_300_VGA) {
2813                u32 tqueue_pos;
2814                u8 tq_state;
2815
2816                tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2817
2818                inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2819                tq_state |= 0xf0;
2820                tq_state &= 0xfc;
2821                tq_state |= (u8)(tqueue_pos >> 8);
2822                outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2823
2824                outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2825
2826                ivideo->caps |= TURBO_QUEUE_CAP;
2827        }
2828#endif
2829
2830#ifdef CONFIG_FB_SIS_315
2831        if(ivideo->sisvga_engine == SIS_315_VGA) {
2832                u32 tempq = 0, templ;
2833                u8  temp;
2834
2835                if(ivideo->chip == XGI_20) {
2836                        switch(ivideo->cmdQueueSize) {
2837                        case (64 * 1024):
2838                                temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2839                                break;
2840                        case (128 * 1024):
2841                        default:
2842                                temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2843                        }
2844                } else {
2845                        switch(ivideo->cmdQueueSize) {
2846                        case (4 * 1024 * 1024):
2847                                temp = SIS_CMD_QUEUE_SIZE_4M;
2848                                break;
2849                        case (2 * 1024 * 1024):
2850                                temp = SIS_CMD_QUEUE_SIZE_2M;
2851                                break;
2852                        case (1 * 1024 * 1024):
2853                                temp = SIS_CMD_QUEUE_SIZE_1M;
2854                                break;
2855                        default:
2856                        case (512 * 1024):
2857                                temp = SIS_CMD_QUEUE_SIZE_512k;
2858                        }
2859                }
2860
2861                outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2862                outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2863
2864                if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2865                        /* Must disable dual pipe on XGI_40. Can't do
2866                         * this in MMIO mode, because it requires
2867                         * setting/clearing a bit in the MMIO fire trigger
2868                         * register.
2869                         */
2870                        if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2871
2872                                MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2873
2874                                outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2875
2876                                tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2877                                MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2878
2879                                tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2880                                MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2881
2882                                writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2883                                writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2884                                writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2885                                writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2886
2887                                MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2888
2889                                sisfb_syncaccel(ivideo);
2890
2891                                outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2892
2893                        }
2894                }
2895
2896                tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2897                MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2898
2899                temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2900                outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2901
2902                tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2903                MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2904
2905                ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2906        }
2907#endif
2908
2909        ivideo->engineok = 1;
2910}
2911
2912static void __devinit
2913sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2914{
2915        u8 reg;
2916        int i;
2917
2918        inSISIDXREG(SISCR, 0x36, reg);
2919        reg &= 0x0f;
2920        if(ivideo->sisvga_engine == SIS_300_VGA) {
2921                ivideo->CRT2LCDType = sis300paneltype[reg];
2922        } else if(ivideo->chip >= SIS_661) {
2923                ivideo->CRT2LCDType = sis661paneltype[reg];
2924        } else {
2925                ivideo->CRT2LCDType = sis310paneltype[reg];
2926                if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2927                        if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2928                           (ivideo->CRT2LCDType != LCD_320x240_3)) {
2929                                ivideo->CRT2LCDType = LCD_320x240;
2930                        }
2931                }
2932        }
2933
2934        if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2935                /* For broken BIOSes: Assume 1024x768, RGB18 */
2936                ivideo->CRT2LCDType = LCD_1024x768;
2937                setSISIDXREG(SISCR,0x36,0xf0,0x02);
2938                setSISIDXREG(SISCR,0x37,0xee,0x01);
2939                printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2940        }
2941
2942        for(i = 0; i < SIS_LCD_NUMBER; i++) {
2943                if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2944                        ivideo->lcdxres = sis_lcd_data[i].xres;
2945                        ivideo->lcdyres = sis_lcd_data[i].yres;
2946                        ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2947                        break;
2948                }
2949        }
2950
2951#ifdef CONFIG_FB_SIS_300
2952        if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2953                ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2954                ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2955        } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2956                ivideo->lcdxres =  848; ivideo->lcdyres =  480;
2957                ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2958        } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2959                ivideo->lcdxres =  856; ivideo->lcdyres =  480;
2960                ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2961        }
2962#endif
2963
2964        printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2965                        ivideo->lcdxres, ivideo->lcdyres);
2966}
2967
2968static void __devinit
2969sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2970{
2971#ifdef CONFIG_FB_SIS_300
2972        /* Save the current PanelDelayCompensation if the LCD is currently used */
2973        if(ivideo->sisvga_engine == SIS_300_VGA) {
2974                if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2975                        int tmp;
2976                        inSISIDXREG(SISCR,0x30,tmp);
2977                        if(tmp & 0x20) {
2978                                /* Currently on LCD? If yes, read current pdc */
2979                                inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
2980                                ivideo->detectedpdc &= 0x3c;
2981                                if(ivideo->SiS_Pr.PDC == -1) {
2982                                        /* Let option override detection */
2983                                        ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2984                                }
2985                                printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2986                                        ivideo->detectedpdc);
2987                        }
2988                        if((ivideo->SiS_Pr.PDC != -1) &&
2989                           (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2990                                printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2991                                        ivideo->SiS_Pr.PDC);
2992                        }
2993                }
2994        }
2995#endif
2996
2997#ifdef CONFIG_FB_SIS_315
2998        if(ivideo->sisvga_engine == SIS_315_VGA) {
2999
3000                /* Try to find about LCDA */
3001                if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3002                        int tmp;
3003                        inSISIDXREG(SISPART1,0x13,tmp);
3004                        if(tmp & 0x04) {
3005                                ivideo->SiS_Pr.SiS_UseLCDA = true;
3006                                ivideo->detectedlcda = 0x03;
3007                        }
3008                }
3009
3010                /* Save PDC */
3011                if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3012                        int tmp;
3013                        inSISIDXREG(SISCR,0x30,tmp);
3014                        if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3015                                /* Currently on LCD? If yes, read current pdc */
3016                                u8 pdc;
3017                                inSISIDXREG(SISPART1,0x2D,pdc);
3018                                ivideo->detectedpdc  = (pdc & 0x0f) << 1;
3019                                ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3020                                inSISIDXREG(SISPART1,0x35,pdc);
3021                                ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3022                                inSISIDXREG(SISPART1,0x20,pdc);
3023                                ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3024                                if(ivideo->newrom) {
3025                                        /* New ROM invalidates other PDC resp. */
3026                                        if(ivideo->detectedlcda != 0xff) {
3027                                                ivideo->detectedpdc = 0xff;
3028                                        } else {
3029                                                ivideo->detectedpdca = 0xff;
3030                                        }
3031                                }
3032                                if(ivideo->SiS_Pr.PDC == -1) {
3033                                        if(ivideo->detectedpdc != 0xff) {
3034                                                ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3035                                        }
3036                                }
3037                                if(ivideo->SiS_Pr.PDCA == -1) {
3038                                        if(ivideo->detectedpdca != 0xff) {
3039                                                ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3040                                        }
3041                                }
3042                                if(ivideo->detectedpdc != 0xff) {
3043                                        printk(KERN_INFO
3044                                                "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3045                                                ivideo->detectedpdc);
3046                                }
3047                                if(ivideo->detectedpdca != 0xff) {
3048                                        printk(KERN_INFO
3049                                                "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3050                                                ivideo->detectedpdca);
3051                                }
3052                        }
3053
3054                        /* Save EMI */
3055                        if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3056                                inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3057                                inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3058                                inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3059                                inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3060                                ivideo->SiS_Pr.HaveEMI = true;
3061                                if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3062                                        ivideo->SiS_Pr.HaveEMILCD = true;
3063                                }
3064                        }
3065                }
3066
3067                /* Let user override detected PDCs (all bridges) */
3068                if(ivideo->vbflags2 & VB2_30xBLV) {
3069                        if((ivideo->SiS_Pr.PDC != -1) &&
3070                           (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3071                                printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3072                                        ivideo->SiS_Pr.PDC);
3073                        }
3074                        if((ivideo->SiS_Pr.PDCA != -1) &&
3075                           (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3076                                printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3077                                 ivideo->SiS_Pr.PDCA);
3078                        }
3079                }
3080
3081        }
3082#endif
3083}
3084
3085/* -------------------- Memory manager routines ---------------------- */
3086
3087static u32 __devinit
3088sisfb_getheapstart(struct sis_video_info *ivideo)
3089{
3090        u32 ret = ivideo->sisfb_parm_mem * 1024;
3091        u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3092        u32 def;
3093
3094        /* Calculate heap start = end of memory for console
3095         *
3096         * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3097         * C = console, D = heap, H = HWCursor, Q = cmd-queue
3098         *
3099         * On 76x in UMA+LFB mode, the layout is as follows:
3100         * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3101         * where the heap is the entire UMA area, eventually
3102         * into the LFB area if the given mem parameter is
3103         * higher than the size of the UMA memory.
3104         *
3105         * Basically given by "mem" parameter
3106         *
3107         * maximum = videosize - cmd_queue - hwcursor
3108         *           (results in a heap of size 0)
3109         * default = SiS 300: depends on videosize
3110         *           SiS 315/330/340/XGI: 32k below max
3111         */
3112
3113        if(ivideo->sisvga_engine == SIS_300_VGA) {
3114                if(ivideo->video_size > 0x1000000) {
3115                        def = 0xc00000;
3116                } else if(ivideo->video_size > 0x800000) {
3117                        def = 0x800000;
3118                } else {
3119                        def = 0x400000;
3120                }
3121        } else if(ivideo->UMAsize && ivideo->LFBsize) {
3122                ret = def = 0;
3123        } else {
3124                def = maxoffs - 0x8000;
3125        }
3126
3127        /* Use default for secondary card for now (FIXME) */
3128        if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3129                ret = def;
3130
3131        return ret;
3132}
3133
3134static u32 __devinit
3135sisfb_getheapsize(struct sis_video_info *ivideo)
3136{
3137        u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3138        u32 ret = 0;
3139
3140        if(ivideo->UMAsize && ivideo->LFBsize) {
3141                if( (!ivideo->sisfb_parm_mem)                        ||
3142                    ((ivideo->sisfb_parm_mem * 1024) > max)        ||
3143                    ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3144                        ret = ivideo->UMAsize;
3145                        max -= ivideo->UMAsize;
3146                } else {
3147                        ret = max - (ivideo->sisfb_parm_mem * 1024);
3148                        max = ivideo->sisfb_parm_mem * 1024;
3149                }
3150                ivideo->video_offset = ret;
3151                ivideo->sisfb_mem = max;
3152        } else {
3153                ret = max - ivideo->heapstart;
3154                ivideo->sisfb_mem = ivideo->heapstart;
3155        }
3156
3157        return ret;
3158}
3159
3160static int __devinit
3161sisfb_heap_init(struct sis_video_info *ivideo)
3162{
3163        struct SIS_OH *poh;
3164
3165        ivideo->video_offset = 0;
3166        if(ivideo->sisfb_parm_mem) {
3167                if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3168                    (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3169                        ivideo->sisfb_parm_mem = 0;
3170                }
3171        }
3172
3173        ivideo->heapstart = sisfb_getheapstart(ivideo);
3174        ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3175
3176        ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3177        ivideo->sisfb_heap_end   = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3178
3179        printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3180                (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3181
3182        ivideo->sisfb_heap.vinfo = ivideo;
3183
3184        ivideo->sisfb_heap.poha_chain = NULL;
3185        ivideo->sisfb_heap.poh_freelist = NULL;
3186
3187        poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3188        if(poh == NULL)
3189                return 1;
3190
3191        poh->poh_next = &ivideo->sisfb_heap.oh_free;
3192        poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3193        poh->size = ivideo->sisfb_heap_size;
3194        poh->offset = ivideo->heapstart;
3195
3196        ivideo->sisfb_heap.oh_free.poh_next = poh;
3197        ivideo->sisfb_heap.oh_free.poh_prev = poh;
3198        ivideo->sisfb_heap.oh_free.size = 0;
3199        ivideo->sisfb_heap.max_freesize = poh->size;
3200
3201        ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3202        ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3203        ivideo->sisfb_heap.oh_used.size = SENTINEL;
3204
3205        if(ivideo->cardnumber == 0) {
3206                /* For the first card, make this heap the "global" one
3207                 * for old DRM (which could handle only one card)
3208                 */
3209                sisfb_heap = &ivideo->sisfb_heap;
3210        }
3211
3212        return 0;
3213}
3214
3215static struct SIS_OH *
3216sisfb_poh_new_node(struct SIS_HEAP *memheap)
3217{
3218        struct SIS_OHALLOC        *poha;
3219        struct SIS_OH                *poh;
3220        unsigned long                cOhs;
3221        int                        i;
3222
3223        if(memheap->poh_freelist == NULL) {
3224                poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3225                if(!poha)
3226                        return NULL;
3227
3228                poha->poha_next = memheap->poha_chain;
3229                memheap->poha_chain = poha;
3230
3231                cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3232
3233                poh = &poha->aoh[0];
3234                for(i = cOhs - 1; i != 0; i--) {
3235                        poh->poh_next = poh + 1;
3236                        poh = poh + 1;
3237                }
3238
3239                poh->poh_next = NULL;
3240                memheap->poh_freelist = &poha->aoh[0];
3241        }
3242
3243        poh = memheap->poh_freelist;
3244        memheap->poh_freelist = poh->poh_next;
3245
3246        return poh;
3247}
3248
3249static struct SIS_OH *
3250sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3251{
3252        struct SIS_OH        *pohThis;
3253        struct SIS_OH        *pohRoot;
3254        int                bAllocated = 0;
3255
3256        if(size > memheap->max_freesize) {
3257                DPRINTK("sisfb: Can't allocate %dk video memory\n",
3258                        (unsigned int) size / 1024);
3259                return NULL;
3260        }
3261
3262        pohThis = memheap->oh_free.poh_next;
3263
3264        while(pohThis != &memheap->oh_free) {
3265                if(size <= pohThis->size) {
3266                        bAllocated = 1;
3267                        break;
3268                }
3269                pohThis = pohThis->poh_next;
3270        }
3271
3272        if(!bAllocated) {
3273                DPRINTK("sisfb: Can't allocate %dk video memory\n",
3274                        (unsigned int) size / 1024);
3275                return NULL;
3276        }
3277
3278        if(size == pohThis->size) {
3279                pohRoot = pohThis;
3280                sisfb_delete_node(pohThis);
3281        } else {
3282                pohRoot = sisfb_poh_new_node(memheap);
3283                if(pohRoot == NULL)
3284                        return NULL;
3285
3286                pohRoot->offset = pohThis->offset;
3287                pohRoot->size = size;
3288
3289                pohThis->offset += size;
3290                pohThis->size -= size;
3291        }
3292
3293        memheap->max_freesize -= size;
3294
3295        pohThis = &memheap->oh_used;
3296        sisfb_insert_node(pohThis, pohRoot);
3297
3298        return pohRoot;
3299}
3300
3301static void
3302sisfb_delete_node(struct SIS_OH *poh)
3303{
3304        poh->poh_prev->poh_next = poh->poh_next;
3305        poh->poh_next->poh_prev = poh->poh_prev;
3306}
3307
3308static void
3309sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3310{
3311        struct SIS_OH *pohTemp = pohList->poh_next;
3312
3313        pohList->poh_next = poh;
3314        pohTemp->poh_prev = poh;
3315
3316        poh->poh_prev = pohList;
3317        poh->poh_next = pohTemp;
3318}
3319
3320static struct SIS_OH *
3321sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3322{
3323        struct SIS_OH *pohThis;
3324        struct SIS_OH *poh_freed;
3325        struct SIS_OH *poh_prev;
3326        struct SIS_OH *poh_next;
3327        u32    ulUpper;
3328        u32    ulLower;
3329        int    foundNode = 0;
3330
3331        poh_freed = memheap->oh_used.poh_next;
3332
3333        while(poh_freed != &memheap->oh_used) {
3334                if(poh_freed->offset == base) {
3335                        foundNode = 1;
3336                        break;
3337                }
3338
3339                poh_freed = poh_freed->poh_next;
3340        }
3341
3342        if(!foundNode)
3343                return NULL;
3344
3345        memheap->max_freesize += poh_freed->size;
3346
3347        poh_prev = poh_next = NULL;
3348        ulUpper = poh_freed->offset + poh_freed->size;
3349        ulLower = poh_freed->offset;
3350
3351        pohThis = memheap->oh_free.poh_next;
3352
3353        while(pohThis != &memheap->oh_free) {
3354                if(pohThis->offset == ulUpper) {
3355                        poh_next = pohThis;
3356                } else if((pohThis->offset + pohThis->size) == ulLower) {
3357                        poh_prev = pohThis;
3358                }
3359                pohThis = pohThis->poh_next;
3360        }
3361
3362        sisfb_delete_node(poh_freed);
3363
3364        if(poh_prev && poh_next) {
3365                poh_prev->size += (poh_freed->size + poh_next->size);
3366                sisfb_delete_node(poh_next);
3367                sisfb_free_node(memheap, poh_freed);
3368                sisfb_free_node(memheap, poh_next);
3369                return poh_prev;
3370        }
3371
3372        if(poh_prev) {
3373                poh_prev->size += poh_freed->size;
3374                sisfb_free_node(memheap, poh_freed);
3375                return poh_prev;
3376        }
3377
3378        if(poh_next) {
3379                poh_next->size += poh_freed->size;
3380                poh_next->offset = poh_freed->offset;
3381                sisfb_free_node(memheap, poh_freed);
3382                return poh_next;
3383        }
3384
3385        sisfb_insert_node(&memheap->oh_free, poh_freed);
3386
3387        return poh_freed;
3388}
3389
3390static void
3391sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3392{
3393        if(poh == NULL)
3394                return;
3395
3396        poh->poh_next = memheap->poh_freelist;
3397        memheap->poh_freelist = poh;
3398}
3399
3400static void
3401sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3402{
3403        struct SIS_OH *poh = NULL;
3404
3405        if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3406                poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3407
3408        if(poh == NULL) {
3409                req->offset = req->size = 0;
3410                DPRINTK("sisfb: Video RAM allocation failed\n");
3411        } else {
3412                req->offset = poh->offset;
3413                req->size = poh->size;
3414                DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3415                        (poh->offset + ivideo->video_vbase));
3416        }
3417}
3418
3419void
3420sis_malloc(struct sis_memreq *req)
3421{
3422        struct sis_video_info *ivideo = sisfb_heap->vinfo;
3423
3424        if(&ivideo->sisfb_heap == sisfb_heap)
3425                sis_int_malloc(ivideo, req);
3426        else
3427                req->offset = req->size = 0;
3428}
3429
3430void
3431sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3432{
3433        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3434
3435        sis_int_malloc(ivideo, req);
3436}
3437
3438/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3439
3440static void
3441sis_int_free(struct sis_video_info *ivideo, u32 base)
3442{
3443        struct SIS_OH *poh;
3444
3445        if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3446                return;
3447
3448        poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3449
3450        if(poh == NULL) {
3451                DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3452                        (unsigned int) base);
3453        }
3454}
3455
3456void
3457sis_free(u32 base)
3458{
3459        struct sis_video_info *ivideo = sisfb_heap->vinfo;
3460
3461        sis_int_free(ivideo, base);
3462}
3463
3464void
3465sis_free_new(struct pci_dev *pdev, u32 base)
3466{
3467        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3468
3469        sis_int_free(ivideo, base);
3470}
3471
3472/* --------------------- SetMode routines ------------------------- */
3473
3474static void
3475sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3476{
3477        u8 cr30, cr31;
3478
3479        /* Check if MMIO and engines are enabled,
3480         * and sync in case they are. Can't use
3481         * ivideo->accel here, as this might have
3482         * been changed before this is called.
3483         */
3484        inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3485        inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3486        /* MMIO and 2D/3D engine enabled? */
3487        if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3488#ifdef CONFIG_FB_SIS_300
3489                if(ivideo->sisvga_engine == SIS_300_VGA) {
3490                        /* Don't care about TurboQueue. It's
3491                         * enough to know that the engines
3492                         * are enabled
3493                         */
3494                        sisfb_syncaccel(ivideo);
3495                }
3496#endif
3497#ifdef CONFIG_FB_SIS_315
3498                if(ivideo->sisvga_engine == SIS_315_VGA) {
3499                        /* Check that any queue mode is
3500                         * enabled, and that the queue
3501                         * is not in the state of "reset"
3502                         */
3503                        inSISIDXREG(SISSR, 0x26, cr30);
3504                        if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3505                                sisfb_syncaccel(ivideo);
3506                        }
3507                }
3508#endif
3509        }
3510}
3511
3512static void
3513sisfb_pre_setmode(struct sis_video_info *ivideo)
3514{
3515        u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3516        int tvregnum = 0;
3517
3518        ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3519
3520        outSISIDXREG(SISSR, 0x05, 0x86);
3521
3522        inSISIDXREG(SISCR, 0x31, cr31);
3523        cr31 &= ~0x60;
3524        cr31 |= 0x04;
3525
3526        cr33 = ivideo->rate_idx & 0x0F;
3527
3528#ifdef CONFIG_FB_SIS_315
3529        if(ivideo->sisvga_engine == SIS_315_VGA) {
3530           if(ivideo->chip >= SIS_661) {
3531              inSISIDXREG(SISCR, 0x38, cr38);
3532              cr38 &= ~0x07;  /* Clear LCDA/DualEdge and YPbPr bits */
3533           } else {
3534              tvregnum = 0x38;
3535              inSISIDXREG(SISCR, tvregnum, cr38);
3536              cr38 &= ~0x3b;  /* Clear LCDA/DualEdge and YPbPr bits */
3537           }
3538        }
3539#endif
3540#ifdef CONFIG_FB_SIS_300
3541        if(ivideo->sisvga_engine == SIS_300_VGA) {
3542           tvregnum = 0x35;
3543           inSISIDXREG(SISCR, tvregnum, cr38);
3544        }
3545#endif
3546
3547        SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3548        SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
3549        ivideo->curFSTN = ivideo->curDSTN = 0;
3550
3551        switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3552
3553           case CRT2_TV:
3554              cr38 &= ~0xc0;   /* Clear PAL-M / PAL-N bits */
3555              if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3556#ifdef CONFIG_FB_SIS_315
3557                 if(ivideo->chip >= SIS_661) {
3558                    cr38 |= 0x04;
3559                    if(ivideo->vbflags & TV_YPBPR525P)       cr35 |= 0x20;
3560                    else if(ivideo->vbflags & TV_YPBPR750P)  cr35 |= 0x40;
3561                    else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3562                    cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3563                    cr35 &= ~0x01;
3564                    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3565                 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3566                    cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3567                    cr38 |= 0x08;
3568                    if(ivideo->vbflags & TV_YPBPR525P)       cr38 |= 0x10;
3569                    else if(ivideo->vbflags & TV_YPBPR750P)  cr38 |= 0x20;
3570                    else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3571                    cr31 &= ~0x01;
3572                    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3573                 }
3574#endif
3575              } else if((ivideo->vbflags & TV_HIVISION) &&
3576                                (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3577                 if(ivideo->chip >= SIS_661) {
3578                    cr38 |= 0x04;
3579                    cr35 |= 0x60;
3580                 } else {
3581                    cr30 |= 0x80;
3582                 }
3583                 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3584                 cr31 |= 0x01;
3585                 cr35 |= 0x01;
3586                 ivideo->currentvbflags |= TV_HIVISION;
3587              } else if(ivideo->vbflags & TV_SCART) {
3588                 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3589                 cr31 |= 0x01;
3590                 cr35 |= 0x01;
3591                 ivideo->currentvbflags |= TV_SCART;
3592              } else {
3593                 if(ivideo->vbflags & TV_SVIDEO) {
3594                    cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3595                    ivideo->currentvbflags |= TV_SVIDEO;
3596                 }
3597                 if(ivideo->vbflags & TV_AVIDEO) {
3598                    cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3599                    ivideo->currentvbflags |= TV_AVIDEO;
3600                 }
3601              }
3602              cr31 |= SIS_DRIVER_MODE;
3603
3604              if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3605                 if(ivideo->vbflags & TV_PAL) {
3606                    cr31 |= 0x01; cr35 |= 0x01;
3607                    ivideo->currentvbflags |= TV_PAL;
3608                    if(ivideo->vbflags & TV_PALM) {
3609                       cr38 |= 0x40; cr35 |= 0x04;
3610                       ivideo->currentvbflags |= TV_PALM;
3611                    } else if(ivideo->vbflags & TV_PALN) {
3612                       cr38 |= 0x80; cr35 |= 0x08;
3613                       ivideo->currentvbflags |= TV_PALN;
3614                    }
3615                 } else {
3616                    cr31 &= ~0x01; cr35 &= ~0x01;
3617                    ivideo->currentvbflags |= TV_NTSC;
3618                    if(ivideo->vbflags & TV_NTSCJ) {
3619                       cr38 |= 0x40; cr35 |= 0x02;
3620                       ivideo->currentvbflags |= TV_NTSCJ;
3621                    }
3622                 }
3623              }
3624              break;
3625
3626           case CRT2_LCD:
3627              cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3628              cr31 |= SIS_DRIVER_MODE;
3629              SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3630              SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3631              ivideo->curFSTN = ivideo->sisfb_fstn;
3632              ivideo->curDSTN = ivideo->sisfb_dstn;
3633              break;
3634
3635           case CRT2_VGA:
3636              cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3637              cr31 |= SIS_DRIVER_MODE;
3638              if(ivideo->sisfb_nocrt2rate) {
3639                 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3640              } else {
3641                 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3642              }
3643              break;
3644
3645           default:        /* disable CRT2 */
3646              cr30 = 0x00;
3647              cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3648        }
3649
3650        outSISIDXREG(SISCR, 0x30, cr30);
3651        outSISIDXREG(SISCR, 0x33, cr33);
3652
3653        if(ivideo->chip >= SIS_661) {
3654#ifdef CONFIG_FB_SIS_315
3655           cr31 &= ~0x01;                          /* Clear PAL flag (now in CR35) */
3656           setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3657           cr38 &= 0x07;                           /* Use only LCDA and HiVision/YPbPr bits */
3658           setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3659#endif
3660        } else if(ivideo->chip != SIS_300) {
3661           outSISIDXREG(SISCR, tvregnum, cr38);
3662        }
3663        outSISIDXREG(SISCR, 0x31, cr31);
3664
3665        ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3666
3667        sisfb_check_engine_and_sync(ivideo);
3668}
3669
3670/* Fix SR11 for 661 and later */
3671#ifdef CONFIG_FB_SIS_315
3672static void
3673sisfb_fixup_SR11(struct sis_video_info *ivideo)
3674{
3675        u8  tmpreg;
3676
3677        if(ivideo->chip >= SIS_661) {
3678                inSISIDXREG(SISSR,0x11,tmpreg);
3679                if(tmpreg & 0x20) {
3680                        inSISIDXREG(SISSR,0x3e,tmpreg);
3681                        tmpreg = (tmpreg + 1) & 0xff;
3682                        outSISIDXREG(SISSR,0x3e,tmpreg);
3683                        inSISIDXREG(SISSR,0x11,tmpreg);
3684                }
3685                if(tmpreg & 0xf0) {
3686                        andSISIDXREG(SISSR,0x11,0x0f);
3687                }
3688        }
3689}
3690#endif
3691
3692static void
3693sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3694{
3695        if(val > 32) val = 32;
3696        if(val < -32) val = -32;
3697        ivideo->tvxpos = val;
3698
3699        if(ivideo->sisfblocked) return;
3700        if(!ivideo->modechanged) return;
3701
3702        if(ivideo->currentvbflags & CRT2_TV) {
3703
3704                if(ivideo->vbflags2 & VB2_CHRONTEL) {
3705
3706                        int x = ivideo->tvx;
3707
3708                        switch(ivideo->chronteltype) {
3709                        case 1:
3710                                x += val;
3711                                if(x < 0) x = 0;
3712                                outSISIDXREG(SISSR,0x05,0x86);
3713                                SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3714                                SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3715                                break;
3716                        case 2:
3717                                /* Not supported by hardware */
3718                                break;
3719                        }
3720
3721                } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3722
3723                        u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3724                        unsigned short temp;
3725
3726                        p2_1f = ivideo->p2_1f;
3727                        p2_20 = ivideo->p2_20;
3728                        p2_2b = ivideo->p2_2b;
3729                        p2_42 = ivideo->p2_42;
3730                        p2_43 = ivideo->p2_43;
3731
3732                        temp = p2_1f | ((p2_20 & 0xf0) << 4);
3733                        temp += (val * 2);
3734                        p2_1f = temp & 0xff;
3735                        p2_20 = (temp & 0xf00) >> 4;
3736                        p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3737                        temp = p2_43 | ((p2_42 & 0xf0) << 4);
3738                        temp += (val * 2);
3739                        p2_43 = temp & 0xff;
3740                        p2_42 = (temp & 0xf00) >> 4;
3741                        outSISIDXREG(SISPART2,0x1f,p2_1f);
3742                        setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3743                        setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3744                        setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3745                        outSISIDXREG(SISPART2,0x43,p2_43);
3746                }
3747        }
3748}
3749
3750static void
3751sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3752{
3753        if(val > 32) val = 32;
3754        if(val < -32) val = -32;
3755        ivideo->tvypos = val;
3756
3757        if(ivideo->sisfblocked) return;
3758        if(!ivideo->modechanged) return;
3759
3760        if(ivideo->currentvbflags & CRT2_TV) {
3761
3762                if(ivideo->vbflags2 & VB2_CHRONTEL) {
3763
3764                        int y = ivideo->tvy;
3765
3766                        switch(ivideo->chronteltype) {
3767                        case 1:
3768                                y -= val;
3769                                if(y < 0) y = 0;
3770                                outSISIDXREG(SISSR,0x05,0x86);
3771                                SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3772                                SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3773                                break;
3774                        case 2:
3775                                /* Not supported by hardware */
3776                                break;
3777                        }
3778
3779                } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3780
3781                        char p2_01, p2_02;
3782                        val /= 2;
3783                        p2_01 = ivideo->p2_01;
3784                        p2_02 = ivideo->p2_02;
3785
3786                        p2_01 += val;
3787                        p2_02 += val;
3788                        if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3789                                while((p2_01 <= 0) || (p2_02 <= 0)) {
3790                                        p2_01 += 2;
3791                                        p2_02 += 2;
3792                                }
3793                        }
3794                        outSISIDXREG(SISPART2,0x01,p2_01);
3795                        outSISIDXREG(SISPART2,0x02,p2_02);
3796                }
3797        }
3798}
3799
3800static void
3801sisfb_post_setmode(struct sis_video_info *ivideo)
3802{
3803        bool crt1isoff = false;
3804        bool doit = true;
3805#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3806        u8 reg;
3807#endif
3808#ifdef CONFIG_FB_SIS_315
3809        u8 reg1;
3810#endif
3811
3812        outSISIDXREG(SISSR, 0x05, 0x86);
3813
3814#ifdef CONFIG_FB_SIS_315
3815        sisfb_fixup_SR11(ivideo);
3816#endif
3817
3818        /* Now we actually HAVE changed the display mode */
3819        ivideo->modechanged = 1;
3820
3821        /* We can't switch off CRT1 if bridge is in slave mode */
3822        if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3823                if(sisfb_bridgeisslave(ivideo)) doit = false;
3824        } else
3825                ivideo->sisfb_crt1off = 0;
3826
3827#ifdef CONFIG_FB_SIS_300
3828        if(ivideo->sisvga_engine == SIS_300_VGA) {
3829                if((ivideo->sisfb_crt1off) && (doit)) {
3830                        crt1isoff = true;
3831                        reg = 0x00;
3832                } else {
3833                        crt1isoff = false;
3834                        reg = 0x80;
3835                }
3836                setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3837        }
3838#endif
3839#ifdef CONFIG_FB_SIS_315
3840        if(ivideo->sisvga_engine == SIS_315_VGA) {
3841                if((ivideo->sisfb_crt1off) && (doit)) {
3842                        crt1isoff = true;
3843                        reg  = 0x40;
3844                        reg1 = 0xc0;
3845                } else {
3846                        crt1isoff = false;
3847                        reg  = 0x00;
3848                        reg1 = 0x00;
3849                }
3850                setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3851                setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3852        }
3853#endif
3854
3855        if(crt1isoff) {
3856                ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3857                ivideo->currentvbflags |= VB_SINGLE_MODE;
3858        } else {
3859                ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3860                if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3861                        ivideo->currentvbflags |= VB_MIRROR_MODE;
3862                } else {
3863                        ivideo->currentvbflags |= VB_SINGLE_MODE;
3864                }
3865        }
3866
3867        andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3868
3869        if(ivideo->currentvbflags & CRT2_TV) {
3870                if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3871                        inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3872                        inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3873                        inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3874                        inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3875                        inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3876                        inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3877                        inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3878                } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3879                        if(ivideo->chronteltype == 1) {
3880                                ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3881                                ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3882                                ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3883                                ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3884                        }
3885                }
3886        }
3887
3888        if(ivideo->tvxpos) {
3889                sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3890        }
3891        if(ivideo->tvypos) {
3892                sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3893        }
3894
3895        /* Eventually sync engines */
3896        sisfb_check_engine_and_sync(ivideo);
3897
3898        /* (Re-)Initialize chip engines */
3899        if(ivideo->accel) {
3900                sisfb_engine_init(ivideo);
3901        } else {
3902                ivideo->engineok = 0;
3903        }
3904}
3905
3906static int
3907sisfb_reset_mode(struct sis_video_info *ivideo)
3908{
3909        if(sisfb_set_mode(ivideo, 0))
3910                return 1;
3911
3912        sisfb_set_pitch(ivideo);
3913        sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3914        sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3915
3916        return 0;
3917}
3918
3919static void
3920sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3921{
3922        int mycrt1off;
3923
3924        switch(sisfb_command->sisfb_cmd) {
3925        case SISFB_CMD_GETVBFLAGS:
3926                if(!ivideo->modechanged) {
3927                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3928                } else {
3929                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3930                        sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3931                        sisfb_command->sisfb_result[2] = ivideo->vbflags2;
3932                }
3933                break;
3934        case SISFB_CMD_SWITCHCRT1:
3935                /* arg[0]: 0 = off, 1 = on, 99 = query */
3936                if(!ivideo->modechanged) {
3937                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3938                } else if(sisfb_command->sisfb_arg[0] == 99) {
3939                        /* Query */
3940                        sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3941                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3942                } else if(ivideo->sisfblocked) {
3943                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3944                } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3945                                        (sisfb_command->sisfb_arg[0] == 0)) {
3946                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3947                } else {
3948                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3949                        mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3950                        if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3951                            ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3952                                ivideo->sisfb_crt1off = mycrt1off;
3953                                if(sisfb_reset_mode(ivideo)) {
3954                                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
3955                                }
3956                        }
3957                        sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3958                }
3959                break;
3960        /* more to come */
3961        default:
3962                sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3963                printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3964                        sisfb_command->sisfb_cmd);
3965        }
3966}
3967
3968#ifndef MODULE
3969static int __init sisfb_setup(char *options)
3970{
3971        char *this_opt;
3972
3973        sisfb_setdefaultparms();
3974
3975        if(!options || !(*options))
3976                return 0;
3977
3978        while((this_opt = strsep(&options, ",")) != NULL) {
3979
3980                if(!(*this_opt)) continue;
3981
3982                if(!strnicmp(this_opt, "off", 3)) {
3983                        sisfb_off = 1;
3984                } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3985                        /* Need to check crt2 type first for fstn/dstn */
3986                        sisfb_search_crt2type(this_opt + 14);
3987                } else if(!strnicmp(this_opt, "tvmode:",7)) {
3988                        sisfb_search_tvstd(this_opt + 7);
3989                } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3990                        sisfb_search_tvstd(this_opt + 11);
3991                } else if(!strnicmp(this_opt, "mode:", 5)) {
3992                        sisfb_search_mode(this_opt + 5, false);
3993                } else if(!strnicmp(this_opt, "vesa:", 5)) {
3994                        sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
3995                } else if(!strnicmp(this_opt, "rate:", 5)) {
3996                        sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
3997                } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3998                        sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
3999                } else if(!strnicmp(this_opt, "mem:",4)) {
4000                        sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4001                } else if(!strnicmp(this_opt, "pdc:", 4)) {
4002                        sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4003                } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4004                        sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4005                } else if(!strnicmp(this_opt, "noaccel", 7)) {
4006                        sisfb_accel = 0;
4007                } else if(!strnicmp(this_opt, "accel", 5)) {
4008                        sisfb_accel = -1;
4009                } else if(!strnicmp(this_opt, "noypan", 6)) {
4010                        sisfb_ypan = 0;
4011                } else if(!strnicmp(this_opt, "ypan", 4)) {
4012                        sisfb_ypan = -1;
4013                } else if(!strnicmp(this_opt, "nomax", 5)) {
4014                        sisfb_max = 0;
4015                } else if(!strnicmp(this_opt, "max", 3)) {
4016                        sisfb_max = -1;
4017                } else if(!strnicmp(this_opt, "userom:", 7)) {
4018                        sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4019                } else if(!strnicmp(this_opt, "useoem:", 7)) {
4020                        sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4021                } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4022                        sisfb_nocrt2rate = 1;
4023                } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4024                        unsigned long temp = 2;
4025                        temp = simple_strtoul(this_opt + 9, NULL, 0);
4026                        if((temp == 0) || (temp == 1)) {
4027                           sisfb_scalelcd = temp ^ 1;
4028                        }
4029                } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4030                        int temp = 0;
4031                        temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4032                        if((temp >= -32) && (temp <= 32)) {
4033                           sisfb_tvxposoffset = temp;
4034                        }
4035                } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4036                        int temp = 0;
4037                        temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4038                        if((temp >= -32) && (temp <= 32)) {
4039                           sisfb_tvyposoffset = temp;
4040                        }
4041                } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4042                        sisfb_search_specialtiming(this_opt + 14);
4043                } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4044                        int temp = 4;
4045                        temp = simple_strtoul(this_opt + 7, NULL, 0);
4046                        if((temp >= 0) && (temp <= 3)) {
4047                           sisfb_lvdshl = temp;
4048                        }
4049                } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4050                        sisfb_search_mode(this_opt, true);
4051#if !defined(__i386__) && !defined(__x86_64__)
4052                } else if(!strnicmp(this_opt, "resetcard", 9)) {
4053                        sisfb_resetcard = 1;
4054                } else if(!strnicmp(this_opt, "videoram:", 9)) {
4055                        sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4056#endif
4057                } else {
4058                        printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4059                }
4060
4061        }
4062
4063        return 0;
4064}
4065#endif
4066
4067static int __devinit
4068sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
4069{
4070        void __iomem *rom;
4071        int romptr;
4072
4073        if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4074                return 0;
4075
4076        romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4077        if(romptr > (0x10000 - 8))
4078                return 0;
4079
4080        rom = rom_base + romptr;
4081
4082        if((readb(rom)     != 'P') || (readb(rom + 1) != 'C') ||
4083           (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4084                return 0;
4085
4086        if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4087                return 0;
4088
4089        if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4090                return 0;
4091
4092        return 1;
4093}
4094
4095static unsigned char * __devinit
4096sisfb_find_rom(struct pci_dev *pdev)
4097{
4098        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4099        void __iomem *rom_base;
4100        unsigned char *myrombase = NULL;
4101        u32 temp;
4102        size_t romsize;
4103
4104        /* First, try the official pci ROM functions (except
4105         * on integrated chipsets which have no ROM).
4106         */
4107
4108        if(!ivideo->nbridge) {
4109
4110                if((rom_base = pci_map_rom(pdev, &romsize))) {
4111
4112                        if(sisfb_check_rom(rom_base, ivideo)) {
4113
4114                                if((myrombase = vmalloc(65536))) {
4115
4116                                        /* Work around bug in pci/rom.c: Folks forgot to check
4117                                         * whether the size retrieved from the BIOS image eventually
4118                                         * is larger than the mapped size
4119                                         */
4120                                        if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4121                                                romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4122
4123                                        memcpy_fromio(myrombase, rom_base,
4124                                                        (romsize > 65536) ? 65536 : romsize);
4125                                }
4126                        }
4127                        pci_unmap_rom(pdev, rom_base);
4128                }
4129        }
4130
4131        if(myrombase) return myrombase;
4132
4133        /* Otherwise do it the conventional way. */
4134
4135#if defined(__i386__) || defined(__x86_64__)
4136
4137        for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4138
4139                rom_base = ioremap(temp, 65536);
4140                if(!rom_base)
4141                        continue;
4142
4143                if(!sisfb_check_rom(rom_base, ivideo)) {
4144                        iounmap(rom_base);
4145                        continue;
4146                }
4147
4148                if((myrombase = vmalloc(65536)))
4149                        memcpy_fromio(myrombase, rom_base, 65536);
4150
4151                iounmap(rom_base);
4152                break;
4153
4154        }
4155
4156#else
4157
4158        pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4159        pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4160                        (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4161
4162        rom_base = ioremap(ivideo->video_base, 65536);
4163        if(rom_base) {
4164                if(sisfb_check_rom(rom_base, ivideo)) {
4165                        if((myrombase = vmalloc(65536)))
4166                                memcpy_fromio(myrombase, rom_base, 65536);
4167                }
4168                iounmap(rom_base);
4169        }
4170
4171        pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4172
4173#endif
4174
4175        return myrombase;
4176}
4177
4178static void __devinit
4179sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4180                        unsigned int min)
4181{
4182        ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4183
4184        if(!ivideo->video_vbase) {
4185                printk(KERN_ERR
4186                        "sisfb: Unable to map maximum video RAM for size detection\n");
4187                (*mapsize) >>= 1;
4188                while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4189                        (*mapsize) >>= 1;
4190                        if((*mapsize) < (min << 20))
4191                                break;
4192                }
4193                if(ivideo->video_vbase) {
4194                        printk(KERN_ERR
4195                                "sisfb: Video RAM size detection limited to %dMB\n",
4196                                (int)((*mapsize) >> 20));
4197                }
4198        }
4199}
4200
4201#ifdef CONFIG_FB_SIS_300
4202static int __devinit
4203sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4204{
4205        void __iomem *FBAddress = ivideo->video_vbase;
4206        unsigned short temp;
4207        unsigned char reg;
4208        int i, j;
4209
4210        andSISIDXREG(SISSR, 0x15, 0xFB);
4211        orSISIDXREG(SISSR, 0x15, 0x04);
4212        outSISIDXREG(SISSR, 0x13, 0x00);
4213        outSISIDXREG(SISSR, 0x14, 0xBF);
4214
4215        for(i = 0; i < 2; i++) {
4216                temp = 0x1234;
4217                for(j = 0; j < 4; j++) {
4218                        writew(temp, FBAddress);
4219                        if(readw(FBAddress) == temp)
4220                                break;
4221                        orSISIDXREG(SISSR, 0x3c, 0x01);
4222                        inSISIDXREG(SISSR, 0x05, reg);
4223                        inSISIDXREG(SISSR, 0x05, reg);
4224                        andSISIDXREG(SISSR, 0x3c, 0xfe);
4225                        inSISIDXREG(SISSR, 0x05, reg);
4226                        inSISIDXREG(SISSR, 0x05, reg);
4227                        temp++;
4228                }
4229        }
4230
4231        writel(0x01234567L, FBAddress);
4232        writel(0x456789ABL, (FBAddress + 4));
4233        writel(0x89ABCDEFL, (FBAddress + 8));
4234        writel(0xCDEF0123L, (FBAddress + 12));
4235
4236        inSISIDXREG(SISSR, 0x3b, reg);
4237        if(reg & 0x01) {
4238                if(readl((FBAddress + 12)) == 0xCDEF0123L)
4239                        return 4;        /* Channel A 128bit */
4240        }
4241
4242        if(readl((FBAddress + 4)) == 0x456789ABL)
4243                return 2;                /* Channel B 64bit */
4244
4245        return 1;                        /* 32bit */
4246}
4247
4248static int __devinit
4249sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4250                        int PseudoRankCapacity, int PseudoAdrPinCount,
4251                        unsigned int mapsize)
4252{
4253        void __iomem *FBAddr = ivideo->video_vbase;
4254        unsigned short sr14;
4255        unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4256        unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4257        static const unsigned short SiS_DRAMType[17][5] = {
4258                {0x0C,0x0A,0x02,0x40,0x39},
4259                {0x0D,0x0A,0x01,0x40,0x48},
4260                {0x0C,0x09,0x02,0x20,0x35},
4261                {0x0D,0x09,0x01,0x20,0x44},
4262                {0x0C,0x08,0x02,0x10,0x31},
4263                {0x0D,0x08,0x01,0x10,0x40},
4264                {0x0C,0x0A,0x01,0x20,0x34},
4265                {0x0C,0x09,0x01,0x08,0x32},
4266                {0x0B,0x08,0x02,0x08,0x21},
4267                {0x0C,0x08,0x01,0x08,0x30},
4268                {0x0A,0x08,0x02,0x04,0x11},
4269                {0x0B,0x0A,0x01,0x10,0x28},
4270                {0x09,0x08,0x02,0x02,0x01},
4271                {0x0B,0x09,0x01,0x08,0x24},
4272                {0x0B,0x08,0x01,0x04,0x20},
4273                {0x0A,0x08,0x01,0x02,0x10},
4274                {0x09,0x08,0x01,0x01,0x00}
4275        };
4276
4277         for(k = 0; k <= 16; k++) {
4278
4279                RankCapacity = buswidth * SiS_DRAMType[k][3];
4280
4281                if(RankCapacity != PseudoRankCapacity)
4282                        continue;
4283
4284                if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4285                        continue;
4286
4287                BankNumHigh = RankCapacity * 16 * iteration - 1;
4288                if(iteration == 3) {             /* Rank No */
4289                        BankNumMid  = RankCapacity * 16 - 1;
4290                } else {
4291                        BankNumMid  = RankCapacity * 16 * iteration / 2 - 1;
4292                }
4293
4294                PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4295                PhysicalAdrHigh = BankNumHigh;
4296                PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4297                PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4298
4299                andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4300                orSISIDXREG(SISSR, 0x15, 0x04);  /* Test */
4301                sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4302                if(buswidth == 4)      sr14 |= 0x80;
4303                else if(buswidth == 2) sr14 |= 0x40;
4304                outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4305                outSISIDXREG(SISSR, 0x14, sr14);
4306
4307                BankNumHigh <<= 16;
4308                BankNumMid <<= 16;
4309
4310                if((BankNumHigh + PhysicalAdrHigh      >= mapsize) ||
4311                   (BankNumMid  + PhysicalAdrHigh      >= mapsize) ||
4312                   (BankNumHigh + PhysicalAdrHalfPage  >= mapsize) ||
4313                   (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4314                        continue;
4315
4316                /* Write data */
4317                writew(((unsigned short)PhysicalAdrHigh),
4318                                (FBAddr + BankNumHigh + PhysicalAdrHigh));
4319                writew(((unsigned short)BankNumMid),
4320                                (FBAddr + BankNumMid  + PhysicalAdrHigh));
4321                writew(((unsigned short)PhysicalAdrHalfPage),
4322                                (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4323                writew(((unsigned short)PhysicalAdrOtherPage),
4324                                (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4325
4326                /* Read data */
4327                if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4328                        return 1;
4329        }
4330
4331        return 0;
4332}
4333
4334static void __devinit
4335sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4336{
4337        struct        sis_video_info *ivideo = pci_get_drvdata(pdev);
4338        int        i, j, buswidth;
4339        int        PseudoRankCapacity, PseudoAdrPinCount;
4340
4341        buswidth = sisfb_post_300_buswidth(ivideo);
4342
4343        for(i = 6; i >= 0; i--) {
4344                PseudoRankCapacity = 1 << i;
4345                for(j = 4; j >= 1; j--) {
4346                        PseudoAdrPinCount = 15 - j;
4347                        if((PseudoRankCapacity * j) <= 64) {
4348                                if(sisfb_post_300_rwtest(ivideo,
4349                                                j,
4350                                                buswidth,
4351                                                PseudoRankCapacity,
4352                                                PseudoAdrPinCount,
4353                                                mapsize))
4354                                        return;
4355                        }
4356                }
4357        }
4358}
4359
4360static void __devinit
4361sisfb_post_sis300(struct pci_dev *pdev)
4362{
4363        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4364        unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4365        u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
4366        u16 index, rindex, memtype = 0;
4367        unsigned int mapsize;
4368
4369        if(!ivideo->SiS_Pr.UseROM)
4370                bios = NULL;
4371
4372        outSISIDXREG(SISSR, 0x05, 0x86);
4373
4374        if(bios) {
4375                if(bios[0x52] & 0x80) {
4376                        memtype = bios[0x52];
4377                } else {
4378                        inSISIDXREG(SISSR, 0x3a, memtype);
4379                }
4380                memtype &= 0x07;
4381        }
4382
4383        v3 = 0x80; v6 = 0x80;
4384        if(ivideo->revision_id <= 0x13) {
4385                v1 = 0x44; v2 = 0x42;
4386                v4 = 0x44; v5 = 0x42;
4387        } else {
4388                v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4389                v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4390                if(bios) {
4391                        index = memtype * 5;
4392                        rindex = index + 0x54;
4393                        v1 = bios[rindex++];
4394                        v2 = bios[rindex++];
4395                        v3 = bios[rindex++];
4396                        rindex = index + 0x7c;
4397                        v4 = bios[rindex++];
4398                        v5 = bios[rindex++];
4399                        v6 = bios[rindex++];
4400                }
4401        }
4402        outSISIDXREG(SISSR, 0x28, v1);
4403        outSISIDXREG(SISSR, 0x29, v2);
4404        outSISIDXREG(SISSR, 0x2a, v3);
4405        outSISIDXREG(SISSR, 0x2e, v4);
4406        outSISIDXREG(SISSR, 0x2f, v5);
4407        outSISIDXREG(SISSR, 0x30, v6);
4408
4409        v1 = 0x10;
4410        if(bios)
4411                v1 = bios[0xa4];
4412        outSISIDXREG(SISSR, 0x07, v1);       /* DAC speed */
4413
4414        outSISIDXREG(SISSR, 0x11, 0x0f);     /* DDC, power save */
4415
4416        v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4417        v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4418        if(bios) {
4419                memtype += 0xa5;
4420                v1 = bios[memtype];
4421                v2 = bios[memtype + 8];
4422                v3 = bios[memtype + 16];
4423                v4 = bios[memtype + 24];
4424                v5 = bios[memtype + 32];
4425                v6 = bios[memtype + 40];
4426                v7 = bios[memtype + 48];
4427                v8 = bios[memtype + 56];
4428        }
4429        if(ivideo->revision_id >= 0x80)
4430                v3 &= 0xfd;
4431        outSISIDXREG(SISSR, 0x15, v1);       /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4432        outSISIDXREG(SISSR, 0x16, v2);
4433        outSISIDXREG(SISSR, 0x17, v3);
4434        outSISIDXREG(SISSR, 0x18, v4);
4435        outSISIDXREG(SISSR, 0x19, v5);
4436        outSISIDXREG(SISSR, 0x1a, v6);
4437        outSISIDXREG(SISSR, 0x1b, v7);
4438        outSISIDXREG(SISSR, 0x1c, v8);           /* ---- */
4439        andSISIDXREG(SISSR, 0x15 ,0xfb);
4440        orSISIDXREG(SISSR, 0x15, 0x04);
4441        if(bios) {
4442                if(bios[0x53] & 0x02) {
4443                        orSISIDXREG(SISSR, 0x19, 0x20);
4444                }
4445        }
4446        v1 = 0x04;                           /* DAC pedestal (BIOS 0xe5) */
4447        if(ivideo->revision_id >= 0x80)
4448                v1 |= 0x01;
4449        outSISIDXREG(SISSR, 0x1f, v1);
4450        outSISIDXREG(SISSR, 0x20, 0xa4);     /* linear & relocated io & disable a0000 */
4451        v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4452        if(bios) {
4453                v1 = bios[0xe8];
4454                v2 = bios[0xe9];
4455                v3 = bios[0xea];
4456        }
4457        outSISIDXREG(SISSR, 0x23, v1);
4458        outSISIDXREG(SISSR, 0x24, v2);
4459        outSISIDXREG(SISSR, 0x25, v3);
4460        outSISIDXREG(SISSR, 0x21, 0x84);
4461        outSISIDXREG(SISSR, 0x22, 0x00);
4462        outSISIDXREG(SISCR, 0x37, 0x00);
4463        orSISIDXREG(SISPART1, 0x24, 0x01);   /* unlock crt2 */
4464        outSISIDXREG(SISPART1, 0x00, 0x00);
4465        v1 = 0x40; v2 = 0x11;
4466        if(bios) {
4467                v1 = bios[0xec];
4468                v2 = bios[0xeb];
4469        }
4470        outSISIDXREG(SISPART1, 0x02, v1);
4471
4472        if(ivideo->revision_id >= 0x80)
4473                v2 &= ~0x01;
4474
4475        inSISIDXREG(SISPART4, 0x00, reg);
4476        if((reg == 1) || (reg == 2)) {
4477                outSISIDXREG(SISCR, 0x37, 0x02);
4478                outSISIDXREG(SISPART2, 0x00, 0x1c);
4479                v4 = 0x00; v5 = 0x00; v6 = 0x10;
4480                if(ivideo->SiS_Pr.UseROM) {
4481                        v4 = bios[0xf5];
4482                        v5 = bios[0xf6];
4483                        v6 = bios[0xf7];
4484                }
4485                outSISIDXREG(SISPART4, 0x0d, v4);
4486                outSISIDXREG(SISPART4, 0x0e, v5);
4487                outSISIDXREG(SISPART4, 0x10, v6);
4488                outSISIDXREG(SISPART4, 0x0f, 0x3f);
4489                inSISIDXREG(SISPART4, 0x01, reg);
4490                if(reg >= 0xb0) {
4491                        inSISIDXREG(SISPART4, 0x23, reg);
4492                        reg &= 0x20;
4493                        reg <<= 1;
4494                        outSISIDXREG(SISPART4, 0x23, reg);
4495                }
4496        } else {
4497                v2 &= ~0x10;
4498        }
4499        outSISIDXREG(SISSR, 0x32, v2);
4500
4501        andSISIDXREG(SISPART1, 0x24, 0xfe);  /* Lock CRT2 */
4502
4503        inSISIDXREG(SISSR, 0x16, reg);
4504        reg &= 0xc3;
4505        outSISIDXREG(SISCR, 0x35, reg);
4506        outSISIDXREG(SISCR, 0x83, 0x00);
4507#if !defined(__i386__) && !defined(__x86_64__)
4508        if(sisfb_videoram) {
4509                outSISIDXREG(SISSR, 0x13, 0x28);  /* ? */
4510                reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4511                outSISIDXREG(SISSR, 0x14, reg);
4512        } else {
4513#endif
4514                /* Need to map max FB size for finding out about RAM size */
4515                mapsize = 64 << 20;
4516                sisfb_post_map_vram(ivideo, &mapsize, 4);
4517
4518                if(ivideo->video_vbase) {
4519                        sisfb_post_300_ramsize(pdev, mapsize);
4520                        iounmap(ivideo->video_vbase);
4521                } else {
4522                        printk(KERN_DEBUG
4523                                "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4524                        outSISIDXREG(SISSR, 0x13, 0x28);  /* ? */
4525                        outSISIDXREG(SISSR, 0x14, 0x47);  /* 8MB, 64bit default */
4526                }
4527#if !defined(__i386__) && !defined(__x86_64__)
4528        }
4529#endif
4530        if(bios) {
4531                v1 = bios[0xe6];
4532                v2 = bios[0xe7];
4533        } else {
4534                inSISIDXREG(SISSR, 0x3a, reg);
4535                if((reg & 0x30) == 0x30) {
4536                        v1 = 0x04; /* PCI */
4537                        v2 = 0x92;
4538                } else {
4539                        v1 = 0x14; /* AGP */
4540                        v2 = 0xb2;
4541                }
4542        }
4543        outSISIDXREG(SISSR, 0x21, v1);
4544        outSISIDXREG(SISSR, 0x22, v2);
4545
4546        /* Sense CRT1 */
4547        sisfb_sense_crt1(ivideo);
4548
4549        /* Set default mode, don't clear screen */
4550        ivideo->SiS_Pr.SiS_UseOEM = false;
4551        SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4552        SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
4553        ivideo->curFSTN = ivideo->curDSTN = 0;
4554        ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4555        SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4556
4557        outSISIDXREG(SISSR, 0x05, 0x86);
4558
4559        /* Display off */
4560        orSISIDXREG(SISSR, 0x01, 0x20);
4561
4562        /* Save mode number in CR34 */
4563        outSISIDXREG(SISCR, 0x34, 0x2e);
4564
4565        /* Let everyone know what the current mode is */
4566        ivideo->modeprechange = 0x2e;
4567}
4568#endif
4569
4570#ifdef CONFIG_FB_SIS_315
4571#if 0
4572static void __devinit
4573sisfb_post_sis315330(struct pci_dev *pdev)
4574{
4575        /* TODO */
4576}
4577#endif
4578
4579static void __devinit
4580sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4581{
4582        unsigned int i;
4583        u8 reg;
4584
4585        for(i = 0; i <= (delay * 10 * 36); i++) {
4586                inSISIDXREG(SISSR, 0x05, reg);
4587                reg++;
4588        }
4589}
4590
4591static int __devinit
4592sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4593                                unsigned short pcivendor)
4594{
4595        struct pci_dev *pdev = NULL;
4596        unsigned short temp;
4597        int ret = 0;
4598
4599        while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
4600                temp = pdev->vendor;
4601                if(temp == pcivendor) {
4602                        ret = 1;
4603                        pci_dev_put(pdev);
4604                        break;
4605                }
4606        }
4607
4608        return ret;
4609}
4610
4611static int __devinit
4612sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4613                        unsigned int enda, unsigned int mapsize)
4614{
4615        unsigned int pos;
4616        int i;
4617
4618        writel(0, ivideo->video_vbase);
4619
4620        for(i = starta; i <= enda; i++) {
4621                pos = 1 << i;
4622                if(pos < mapsize)
4623                        writel(pos, ivideo->video_vbase + pos);
4624        }
4625
4626        sisfb_post_xgi_delay(ivideo, 150);
4627
4628        if(readl(ivideo->video_vbase) != 0)
4629                return 0;
4630
4631        for(i = starta; i <= enda; i++) {
4632                pos = 1 << i;
4633                if(pos < mapsize) {
4634                        if(readl(ivideo->video_vbase + pos) != pos)
4635                                return 0;
4636                } else
4637                        return 0;
4638        }
4639
4640        return 1;
4641}
4642
4643static void __devinit
4644sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4645{
4646        unsigned int buswidth, ranksize, channelab, mapsize;
4647        int i, j, k, l;
4648        u8 reg, sr14;
4649        static const u8 dramsr13[12 * 5] = {
4650                0x02, 0x0e, 0x0b, 0x80, 0x5d,
4651                0x02, 0x0e, 0x0a, 0x40, 0x59,
4652                0x02, 0x0d, 0x0b, 0x40, 0x4d,
4653                0x02, 0x0e, 0x09, 0x20, 0x55,
4654                0x02, 0x0d, 0x0a, 0x20, 0x49,
4655                0x02, 0x0c, 0x0b, 0x20, 0x3d,
4656                0x02, 0x0e, 0x08, 0x10, 0x51,
4657                0x02, 0x0d, 0x09, 0x10, 0x45,
4658                0x02, 0x0c, 0x0a, 0x10, 0x39,
4659                0x02, 0x0d, 0x08, 0x08, 0x41,
4660                0x02, 0x0c, 0x09, 0x08, 0x35,
4661                0x02, 0x0c, 0x08, 0x04, 0x31
4662        };
4663        static const u8 dramsr13_4[4 * 5] = {
4664                0x02, 0x0d, 0x09, 0x40, 0x45,
4665                0x02, 0x0c, 0x09, 0x20, 0x35,
4666                0x02, 0x0c, 0x08, 0x10, 0x31,
4667                0x02, 0x0b, 0x08, 0x08, 0x21
4668        };
4669
4670        /* Enable linear mode, disable 0xa0000 address decoding */
4671        /* We disable a0000 address decoding, because
4672         * - if running on x86, if the card is disabled, it means
4673         *   that another card is in the system. We don't want
4674         *   to interphere with that primary card's textmode.
4675         * - if running on non-x86, there usually is no VGA window
4676         *   at a0000.
4677         */
4678        orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4679
4680        /* Need to map max FB size for finding out about RAM size */
4681        mapsize = 256 << 20;
4682        sisfb_post_map_vram(ivideo, &mapsize, 32);
4683
4684        if(!ivideo->video_vbase) {
4685                printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4686                outSISIDXREG(SISSR, 0x13, 0x35);
4687                outSISIDXREG(SISSR, 0x14, 0x41);
4688                /* TODO */
4689                return;
4690        }
4691
4692        /* Non-interleaving */
4693        outSISIDXREG(SISSR, 0x15, 0x00);
4694        /* No tiling */
4695        outSISIDXREG(SISSR, 0x1c, 0x00);
4696
4697        if(ivideo->chip == XGI_20) {
4698
4699                channelab = 1;
4700                inSISIDXREG(SISCR, 0x97, reg);
4701                if(!(reg & 0x01)) {        /* Single 32/16 */
4702                        buswidth = 32;
4703                        outSISIDXREG(SISSR, 0x13, 0xb1);
4704                        outSISIDXREG(SISSR, 0x14, 0x52);
4705                        sisfb_post_xgi_delay(ivideo, 1);
4706                        sr14 = 0x02;
4707                        if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4708                                goto bail_out;
4709
4710                        outSISIDXREG(SISSR, 0x13, 0x31);
4711                        outSISIDXREG(SISSR, 0x14, 0x42);
4712                        sisfb_post_xgi_delay(ivideo, 1);
4713                        if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4714                                goto bail_out;
4715
4716                        buswidth = 16;
4717                        outSISIDXREG(SISSR, 0x13, 0xb1);
4718                        outSISIDXREG(SISSR, 0x14, 0x41);
4719                        sisfb_post_xgi_delay(ivideo, 1);
4720                        sr14 = 0x01;
4721                        if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4722                                goto bail_out;
4723                        else
4724                                outSISIDXREG(SISSR, 0x13, 0x31);
4725                } else {                /* Dual 16/8 */
4726                        buswidth = 16;
4727                        outSISIDXREG(SISSR, 0x13, 0xb1);
4728                        outSISIDXREG(SISSR, 0x14, 0x41);
4729                        sisfb_post_xgi_delay(ivideo, 1);
4730                        sr14 = 0x01;
4731                        if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4732                                goto bail_out;
4733
4734                        outSISIDXREG(SISSR, 0x13, 0x31);
4735                        outSISIDXREG(SISSR, 0x14, 0x31);
4736                        sisfb_post_xgi_delay(ivideo, 1);
4737                        if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4738                                goto bail_out;
4739
4740                        buswidth = 8;
4741                        outSISIDXREG(SISSR, 0x13, 0xb1);
4742                        outSISIDXREG(SISSR, 0x14, 0x30);
4743                        sisfb_post_xgi_delay(ivideo, 1);
4744                        sr14 = 0x00;
4745                        if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4746                                goto bail_out;
4747                        else
4748                                outSISIDXREG(SISSR, 0x13, 0x31);
4749                }
4750
4751        } else {        /* XGI_40 */
4752
4753                inSISIDXREG(SISCR, 0x97, reg);
4754                if(!(reg & 0x10)) {
4755                        inSISIDXREG(SISSR, 0x39, reg);
4756                        reg >>= 1;
4757                }
4758
4759                if(reg & 0x01) {        /* DDRII */
4760                        buswidth = 32;
4761                        if(ivideo->revision_id == 2) {
4762                                channelab = 2;
4763                                outSISIDXREG(SISSR, 0x13, 0xa1);
4764                                outSISIDXREG(SISSR, 0x14, 0x44);
4765                                sr14 = 0x04;
4766                                sisfb_post_xgi_delay(ivideo, 1);
4767                                if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4768                                        goto bail_out;
4769
4770                                outSISIDXREG(SISSR, 0x13, 0x21);
4771                                outSISIDXREG(SISSR, 0x14, 0x34);
4772                                if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4773                                        goto bail_out;
4774
4775                                channelab = 1;
4776                                outSISIDXREG(SISSR, 0x13, 0xa1);
4777                                outSISIDXREG(SISSR, 0x14, 0x40);
4778                                sr14 = 0x00;
4779                                if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4780                                        goto bail_out;
4781
4782                                outSISIDXREG(SISSR, 0x13, 0x21);
4783                                outSISIDXREG(SISSR, 0x14, 0x30);
4784                        } else {
4785                                channelab = 3;
4786                                outSISIDXREG(SISSR, 0x13, 0xa1);
4787                                outSISIDXREG(SISSR, 0x14, 0x4c);
4788                                sr14 = 0x0c;
4789                                sisfb_post_xgi_delay(ivideo, 1);
4790                                if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4791                                        goto bail_out;
4792
4793                                channelab = 2;
4794                                outSISIDXREG(SISSR, 0x14, 0x48);
4795                                sisfb_post_xgi_delay(ivideo, 1);
4796                                sr14 = 0x08;
4797                                if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4798                                        goto bail_out;
4799
4800                                outSISIDXREG(SISSR, 0x13, 0x21);
4801                                outSISIDXREG(SISSR, 0x14, 0x3c);
4802                                sr14 = 0x0c;
4803
4804                                if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4805                                        channelab = 3;
4806                                } else {
4807                                        channelab = 2;
4808                                        outSISIDXREG(SISSR, 0x14, 0x38);
4809                                        sr14 = 0x08;
4810                                }
4811                        }
4812                        sisfb_post_xgi_delay(ivideo, 1);
4813
4814                } else {        /* DDR */
4815
4816                        buswidth = 64;
4817                        if(ivideo->revision_id == 2) {
4818                                channelab = 1;
4819                                outSISIDXREG(SISSR, 0x13, 0xa1);
4820                                outSISIDXREG(SISSR, 0x14, 0x52);
4821                                sisfb_post_xgi_delay(ivideo, 1);
4822                                sr14 = 0x02;
4823                                if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4824                                        goto bail_out;
4825
4826                                outSISIDXREG(SISSR, 0x13, 0x21);
4827                                outSISIDXREG(SISSR, 0x14, 0x42);
4828                        } else {
4829                                channelab = 2;
4830                                outSISIDXREG(SISSR, 0x13, 0xa1);
4831                                outSISIDXREG(SISSR, 0x14, 0x5a);
4832                                sisfb_post_xgi_delay(ivideo, 1);
4833                                sr14 = 0x0a;
4834                                if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4835                                        goto bail_out;
4836
4837                                outSISIDXREG(SISSR, 0x13, 0x21);
4838                                outSISIDXREG(SISSR, 0x14, 0x4a);
4839                        }
4840                        sisfb_post_xgi_delay(ivideo, 1);
4841
4842                }
4843        }
4844
4845bail_out:
4846        setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4847        sisfb_post_xgi_delay(ivideo, 1);
4848
4849        j = (ivideo->chip == XGI_20) ? 5 : 9;
4850        k = (ivideo->chip == XGI_20) ? 12 : 4;
4851
4852        for(i = 0; i < k; i++) {
4853
4854                reg = (ivideo->chip == XGI_20) ?
4855                                dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4856                setSISIDXREG(SISSR, 0x13, 0x80, reg);
4857                sisfb_post_xgi_delay(ivideo, 50);
4858
4859                ranksize = (ivideo->chip == XGI_20) ?
4860                                dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4861
4862                inSISIDXREG(SISSR, 0x13, reg);
4863                if(reg & 0x80) ranksize <<= 1;
4864
4865                if(ivideo->chip == XGI_20) {
4866                        if(buswidth == 16)      ranksize <<= 1;
4867                        else if(buswidth == 32) ranksize <<= 2;
4868                } else {
4869                        if(buswidth == 64)      ranksize <<= 1;
4870                }
4871
4872                reg = 0;
4873                l = channelab;
4874                if(l == 3) l = 4;
4875                if((ranksize * l) <= 256) {
4876                        while((ranksize >>= 1)) reg += 0x10;
4877                }
4878
4879                if(!reg) continue;
4880
4881                setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4882                sisfb_post_xgi_delay(ivideo, 1);
4883
4884                if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4885                        break;
4886        }
4887
4888        iounmap(ivideo->video_vbase);
4889}
4890
4891static void __devinit
4892sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4893{
4894        u8 v1, v2, v3;
4895        int index;
4896        static const u8 cs90[8 * 3] = {
4897                0x16, 0x01, 0x01,
4898                0x3e, 0x03, 0x01,
4899                0x7c, 0x08, 0x01,
4900                0x79, 0x06, 0x01,
4901                0x29, 0x01, 0x81,
4902                0x5c, 0x23, 0x01,
4903                0x5c, 0x23, 0x01,
4904                0x5c, 0x23, 0x01
4905        };
4906        static const u8 csb8[8 * 3] = {
4907                0x5c, 0x23, 0x01,
4908                0x29, 0x01, 0x01,
4909                0x7c, 0x08, 0x01,
4910                0x79, 0x06, 0x01,
4911                0x29, 0x01, 0x81,
4912                0x5c, 0x23, 0x01,
4913                0x5c, 0x23, 0x01,
4914                0x5c, 0x23, 0x01
4915        };
4916
4917        regb = 0;  /* ! */
4918
4919        index = regb * 3;
4920        v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4921        if(ivideo->haveXGIROM) {
4922                v1 = ivideo->bios_abase[0x90 + index];
4923                v2 = ivideo->bios_abase[0x90 + index + 1];
4924                v3 = ivideo->bios_abase[0x90 + index + 2];
4925        }
4926        outSISIDXREG(SISSR, 0x28, v1);
4927        outSISIDXREG(SISSR, 0x29, v2);
4928        outSISIDXREG(SISSR, 0x2a, v3);
4929        sisfb_post_xgi_delay(ivideo, 0x43);
4930        sisfb_post_xgi_delay(ivideo, 0x43);
4931        sisfb_post_xgi_delay(ivideo, 0x43);
4932        index = regb * 3;
4933        v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4934        if(ivideo->haveXGIROM) {
4935                v1 = ivideo->bios_abase[0xb8 + index];
4936                v2 = ivideo->bios_abase[0xb8 + index + 1];
4937                v3 = ivideo->bios_abase[0xb8 + index + 2];
4938        }
4939        outSISIDXREG(SISSR, 0x2e, v1);
4940        outSISIDXREG(SISSR, 0x2f, v2);
4941        outSISIDXREG(SISSR, 0x30, v3);
4942        sisfb_post_xgi_delay(ivideo, 0x43);
4943        sisfb_post_xgi_delay(ivideo, 0x43);
4944        sisfb_post_xgi_delay(ivideo, 0x43);
4945}
4946
4947static int __devinit
4948sisfb_post_xgi(struct pci_dev *pdev)
4949{
4950        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4951        unsigned char *bios = ivideo->bios_abase;
4952        struct pci_dev *mypdev = NULL;
4953        const u8 *ptr, *ptr2;
4954        u8 v1, v2, v3, v4, v5, reg, ramtype;
4955        u32 rega, regb, regd;
4956        int i, j, k, index;
4957        static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4958        static const u8 cs76[2] = { 0xa3, 0xfb };
4959        static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4960        static const u8 cs158[8] = {
4961                0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4962        };
4963        static const u8 cs160[8] = {
4964                0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4965        };
4966        static const u8 cs168[8] = {
4967                0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4968        };
4969        static const u8 cs128[3 * 8] = {
4970                0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4971                0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4972                0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4973        };
4974        static const u8 cs148[2 * 8] = {
4975                0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4976                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4977        };
4978        static const u8 cs31a[8 * 4] = {
4979                0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
4980                0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
4981                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4982                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4983        };
4984        static const u8 cs33a[8 * 4] = {
4985                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4986                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4987                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4988                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4989        };
4990        static const u8 cs45a[8 * 2] = {
4991                0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
4992                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4993        };
4994        static const u8 cs170[7 * 8] = {
4995                0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4996                0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4997                0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
4998                0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4999                0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5000                0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5001                0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5002        };
5003        static const u8 cs1a8[3 * 8] = {
5004                0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5005                0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5006                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5007        };
5008        static const u8 cs100[2 * 8] = {
5009                0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5010                0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5011        };
5012
5013        /* VGA enable */
5014        reg = inSISREG(SISVGAENABLE) | 0x01;
5015        outSISREG(SISVGAENABLE, reg);
5016
5017        /* Misc */
5018        reg = inSISREG(SISMISCR) | 0x01;
5019        outSISREG(SISMISCW, reg);
5020
5021        /* Unlock SR */
5022        outSISIDXREG(SISSR, 0x05, 0x86);
5023        inSISIDXREG(SISSR, 0x05, reg);
5024        if(reg != 0xa1)
5025                return 0;
5026
5027        /* Clear some regs */
5028        for(i = 0; i < 0x22; i++) {
5029                if(0x06 + i == 0x20) continue;
5030                outSISIDXREG(SISSR, 0x06 + i, 0x00);
5031        }
5032        for(i = 0; i < 0x0b; i++) {
5033                outSISIDXREG(SISSR, 0x31 + i, 0x00);
5034        }
5035        for(i = 0; i < 0x10; i++) {
5036                outSISIDXREG(SISCR, 0x30 + i, 0x00);
5037        }
5038
5039        ptr = cs78;
5040        if(ivideo->haveXGIROM) {
5041                ptr = (const u8 *)&bios[0x78];
5042        }
5043        for(i = 0; i < 3; i++) {
5044                outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5045        }
5046
5047        ptr = cs76;
5048        if(ivideo->haveXGIROM) {
5049                ptr = (const u8 *)&bios[0x76];
5050        }
5051        for(i = 0; i < 2; i++) {
5052                outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5053        }
5054
5055        v1 = 0x18; v2 = 0x00;
5056        if(ivideo->haveXGIROM) {
5057                v1 = bios[0x74];
5058                v2 = bios[0x75];
5059        }
5060        outSISIDXREG(SISSR, 0x07, v1);
5061        outSISIDXREG(SISSR, 0x11, 0x0f);
5062        outSISIDXREG(SISSR, 0x1f, v2);
5063        /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5064        outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5065        outSISIDXREG(SISSR, 0x27, 0x74);
5066
5067        ptr = cs7b;
5068        if(ivideo->haveXGIROM) {
5069                ptr = (const u8 *)&bios[0x7b];
5070        }
5071        for(i = 0; i < 3; i++) {
5072                outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5073        }
5074
5075        if(ivideo->chip == XGI_40) {
5076                if(ivideo->revision_id == 2) {
5077                        setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5078                }
5079                outSISIDXREG(SISCR, 0x7d, 0xfe);
5080                outSISIDXREG(SISCR, 0x7e, 0x0f);
5081        }
5082        if(ivideo->revision_id == 0) {        /* 40 *and* 20? */
5083                andSISIDXREG(SISCR, 0x58, 0xd7);
5084                inSISIDXREG(SISCR, 0xcb, reg);
5085                if(reg & 0x20) {
5086                        setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5087                }
5088        }
5089
5090        reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5091        setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5092
5093        if(ivideo->chip == XGI_20) {
5094                outSISIDXREG(SISSR, 0x36, 0x70);
5095        } else {
5096                outSISIDXREG(SISVID, 0x00, 0x86);
5097                outSISIDXREG(SISVID, 0x32, 0x00);
5098                outSISIDXREG(SISVID, 0x30, 0x00);
5099                outSISIDXREG(SISVID, 0x32, 0x01);
5100                outSISIDXREG(SISVID, 0x30, 0x00);
5101                andSISIDXREG(SISVID, 0x2f, 0xdf);
5102                andSISIDXREG(SISCAP, 0x00, 0x3f);
5103
5104                outSISIDXREG(SISPART1, 0x2f, 0x01);
5105                outSISIDXREG(SISPART1, 0x00, 0x00);
5106                outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5107                outSISIDXREG(SISPART1, 0x2e, 0x08);
5108                andSISIDXREG(SISPART1, 0x35, 0x7f);
5109                andSISIDXREG(SISPART1, 0x50, 0xfe);
5110
5111                inSISIDXREG(SISPART4, 0x00, reg);
5112                if(reg == 1 || reg == 2) {
5113                        outSISIDXREG(SISPART2, 0x00, 0x1c);
5114                        outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5115                        outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5116                        outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5117                        andSISIDXREG(SISPART4, 0x0f, 0x3f);
5118
5119                        inSISIDXREG(SISPART4, 0x01, reg);
5120                        if((reg & 0xf0) >= 0xb0) {
5121                                inSISIDXREG(SISPART4, 0x23, reg);
5122                                if(reg & 0x20) reg |= 0x40;
5123                                outSISIDXREG(SISPART4, 0x23, reg);
5124                                reg = (reg & 0x20) ? 0x02 : 0x00;
5125                                setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5126                        }
5127                }
5128
5129                v1 = bios[0x77];
5130
5131                inSISIDXREG(SISSR, 0x3b, reg);
5132                if(reg & 0x02) {
5133                        inSISIDXREG(SISSR, 0x3a, reg);
5134                        v2 = (reg & 0x30) >> 3;
5135                        if(!(v2 & 0x04)) v2 ^= 0x02;
5136                        inSISIDXREG(SISSR, 0x39, reg);
5137                        if(reg & 0x80) v2 |= 0x80;
5138                        v2 |= 0x01;
5139
5140                        if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5141                                pci_dev_put(mypdev);
5142                                if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5143                                        v2 &= 0xf9;
5144                                v2 |= 0x08;
5145                                v1 &= 0xfe;
5146                        } else {
5147                                mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
5148                                if(!mypdev)
5149                                        mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
5150                                if(!mypdev)
5151                                        mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
5152                                if(mypdev) {
5153                                        pci_read_config_dword(mypdev, 0x94, &regd);
5154                                        regd &= 0xfffffeff;
5155                                        pci_write_config_dword(mypdev, 0x94, regd);
5156                                        v1 &= 0xfe;
5157                                        pci_dev_put(mypdev);
5158                                } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5159                                        v1 &= 0xfe;
5160                                } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5161                                          sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5162                                          sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5163                                          sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5164                                        if((v2 & 0x06) == 4)
5165                                                v2 ^= 0x06;
5166                                        v2 |= 0x08;
5167                                }
5168                        }
5169                        setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5170                }
5171                outSISIDXREG(SISSR, 0x22, v1);
5172
5173                if(ivideo->revision_id == 2) {
5174                        inSISIDXREG(SISSR, 0x3b, v1);
5175                        inSISIDXREG(SISSR, 0x3a, v2);
5176                        regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5177                        if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5178                                setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5179
5180                        if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
5181                                /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5182                                 * of nforce 2 ROM
5183                                 */
5184                                if(0)
5185                                        setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5186                                pci_dev_put(mypdev);
5187                        }
5188                }
5189
5190                v1 = 0x30;
5191                inSISIDXREG(SISSR, 0x3b, reg);
5192                inSISIDXREG(SISCR, 0x5f, v2);
5193                if((!(reg & 0x02)) && (v2 & 0x0e))
5194                        v1 |= 0x08;
5195                outSISIDXREG(SISSR, 0x27, v1);
5196
5197                if(bios[0x64] & 0x01) {
5198                        setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5199                }
5200
5201                v1 = bios[0x4f7];
5202                pci_read_config_dword(pdev, 0x50, &regd);
5203                regd = (regd >> 20) & 0x0f;
5204                if(regd == 1) {
5205                        v1 &= 0xfc;
5206                        orSISIDXREG(SISCR, 0x5f, 0x08);
5207                }
5208                outSISIDXREG(SISCR, 0x48, v1);
5209
5210                setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5211                setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5212                setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5213                setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5214                setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5215                outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5216                setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5217                outSISIDXREG(SISCR, 0x74, 0xd0);
5218                setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5219                setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5220                setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5221                v1 = bios[0x501];
5222                if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
5223                        v1 = 0xf0;
5224                        pci_dev_put(mypdev);
5225                }
5226                outSISIDXREG(SISCR, 0x77, v1);
5227        }
5228
5229        /* RAM type */
5230
5231        regb = 0;        /* ! */
5232
5233        v1 = 0xff;
5234        if(ivideo->haveXGIROM) {
5235                v1 = bios[0x140 + regb];
5236        }
5237        outSISIDXREG(SISCR, 0x6d, v1);
5238
5239        ptr = cs128;
5240        if(ivideo->haveXGIROM) {
5241                ptr = (const u8 *)&bios[0x128];
5242        }
5243        for(i = 0, j = 0; i < 3; i++, j += 8) {
5244                outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5245        }
5246
5247        ptr  = cs31a;
5248        ptr2 = cs33a;
5249        if(ivideo->haveXGIROM) {
5250                index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5251                ptr  = (const u8 *)&bios[index];
5252                ptr2 = (const u8 *)&bios[index + 0x20];
5253        }
5254        for(i = 0; i < 2; i++) {
5255                if(i == 0) {
5256                        regd = le32_to_cpu(((u32 *)ptr)[regb]);
5257                        rega = 0x6b;
5258                } else {
5259                        regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5260                        rega = 0x6e;
5261                }
5262                reg = 0x00;
5263                for(j = 0; j < 16; j++) {
5264                        reg &= 0xf3;
5265                        if(regd & 0x01) reg |= 0x04;
5266                        if(regd & 0x02) reg |= 0x08;
5267                        regd >>= 2;
5268                        outSISIDXREG(SISCR, rega, reg);
5269                        inSISIDXREG(SISCR, rega, reg);
5270                        inSISIDXREG(SISCR, rega, reg);
5271                        reg += 0x10;
5272                }
5273        }
5274
5275        andSISIDXREG(SISCR, 0x6e, 0xfc);
5276
5277        ptr  = NULL;
5278        if(ivideo->haveXGIROM) {
5279                index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5280                ptr  = (const u8 *)&bios[index];
5281        }
5282        for(i = 0; i < 4; i++) {
5283                setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5284                reg = 0x00;
5285                for(j = 0; j < 2; j++) {
5286                        regd = 0;
5287                        if(ptr) {
5288                                regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5289                                ptr += 4;
5290                        }
5291                        /* reg = 0x00; */
5292                        for(k = 0; k < 16; k++) {
5293                                reg &= 0xfc;
5294                                if(regd & 0x01) reg |= 0x01;
5295                                if(regd & 0x02) reg |= 0x02;
5296                                regd >>= 2;
5297                                outSISIDXREG(SISCR, 0x6f, reg);
5298                                inSISIDXREG(SISCR, 0x6f, reg);
5299                                inSISIDXREG(SISCR, 0x6f, reg);
5300                                reg += 0x08;
5301                        }
5302                }
5303        }
5304
5305        ptr  = cs148;
5306        if(ivideo->haveXGIROM) {
5307                ptr  = (const u8 *)&bios[0x148];
5308        }
5309        for(i = 0, j = 0; i < 2; i++, j += 8) {
5310                outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5311        }
5312
5313        andSISIDXREG(SISCR, 0x89, 0x8f);
5314
5315        ptr  = cs45a;
5316        if(ivideo->haveXGIROM) {
5317                index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5318                ptr  = (const u8 *)&bios[index];
5319        }
5320        regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5321        reg = 0x80;
5322        for(i = 0; i < 5; i++) {
5323                reg &= 0xfc;
5324                if(regd & 0x01) reg |= 0x01;
5325                if(regd & 0x02) reg |= 0x02;
5326                regd >>= 2;
5327                outSISIDXREG(SISCR, 0x89, reg);
5328                inSISIDXREG(SISCR, 0x89, reg);
5329                inSISIDXREG(SISCR, 0x89, reg);
5330                reg += 0x10;
5331        }
5332
5333        v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5334        if(ivideo->haveXGIROM) {
5335                v1 = bios[0x118 + regb];
5336                v2 = bios[0xf8 + regb];
5337                v3 = bios[0x120 + regb];
5338                v4 = bios[0x1ca];
5339        }
5340        outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5341        outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5342        orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5343        outSISIDXREG(SISCR, 0x41, v2);
5344
5345        ptr  = cs170;
5346        if(ivideo->haveXGIROM) {
5347                ptr  = (const u8 *)&bios[0x170];
5348        }
5349        for(i = 0, j = 0; i < 7; i++, j += 8) {
5350                outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5351        }
5352
5353        outSISIDXREG(SISCR, 0x59, v3);
5354
5355        ptr  = cs1a8;
5356        if(ivideo->haveXGIROM) {
5357                ptr  = (const u8 *)&bios[0x1a8];
5358        }
5359        for(i = 0, j = 0; i < 3; i++, j += 8) {
5360                outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5361        }
5362
5363        ptr  = cs100;
5364        if(ivideo->haveXGIROM) {
5365                ptr  = (const u8 *)&bios[0x100];
5366        }
5367        for(i = 0, j = 0; i < 2; i++, j += 8) {
5368                outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5369        }
5370
5371        outSISIDXREG(SISCR, 0xcf, v4);
5372
5373        outSISIDXREG(SISCR, 0x83, 0x09);
5374        outSISIDXREG(SISCR, 0x87, 0x00);
5375
5376        if(ivideo->chip == XGI_40) {
5377                if( (ivideo->revision_id == 1) ||
5378                    (ivideo->revision_id == 2) ) {
5379                        outSISIDXREG(SISCR, 0x8c, 0x87);
5380                }
5381        }
5382
5383        outSISIDXREG(SISSR, 0x17, 0x00);
5384        outSISIDXREG(SISSR, 0x1a, 0x87);
5385
5386        if(ivideo->chip == XGI_20) {
5387                outSISIDXREG(SISSR, 0x15, 0x00);
5388                outSISIDXREG(SISSR, 0x1c, 0x00);
5389        }
5390
5391        ramtype = 0x00; v1 = 0x10;
5392        if(ivideo->haveXGIROM) {
5393                ramtype = bios[0x62];
5394                v1 = bios[0x1d2];
5395        }
5396        if(!(ramtype & 0x80)) {
5397                if(ivideo->chip == XGI_20) {
5398                        outSISIDXREG(SISCR, 0x97, v1);
5399                        inSISIDXREG(SISCR, 0x97, reg);
5400                        if(reg & 0x10) {
5401                                ramtype = (reg & 0x01) << 1;
5402                        }
5403                } else {
5404                        inSISIDXREG(SISSR, 0x39, reg);
5405                        ramtype = reg & 0x02;
5406                        if(!(ramtype)) {
5407                                inSISIDXREG(SISSR, 0x3a, reg);
5408                                ramtype = (reg >> 1) & 0x01;
5409                        }
5410                }
5411        }
5412        ramtype &= 0x07;
5413
5414        regb = 0;        /* ! */
5415
5416        switch(ramtype) {
5417        case 0:
5418                sisfb_post_xgi_setclocks(ivideo, regb);
5419                if((ivideo->chip == XGI_20) ||
5420                   (ivideo->revision_id == 1)   ||
5421                   (ivideo->revision_id == 2)) {
5422                        v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5423                        if(ivideo->haveXGIROM) {
5424                                v1 = bios[regb + 0x158];
5425                                v2 = bios[regb + 0x160];
5426                                v3 = bios[regb + 0x168];
5427                        }
5428                        outSISIDXREG(SISCR, 0x82, v1);
5429                        outSISIDXREG(SISCR, 0x85, v2);
5430                        outSISIDXREG(SISCR, 0x86, v3);
5431                } else {
5432                        outSISIDXREG(SISCR, 0x82, 0x88);
5433                        outSISIDXREG(SISCR, 0x86, 0x00);
5434                        inSISIDXREG(SISCR, 0x86, reg);
5435                        outSISIDXREG(SISCR, 0x86, 0x88);
5436                        inSISIDXREG(SISCR, 0x86, reg);
5437                        outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5438                        outSISIDXREG(SISCR, 0x82, 0x77);
5439                        outSISIDXREG(SISCR, 0x85, 0x00);
5440                        inSISIDXREG(SISCR, 0x85, reg);
5441                        outSISIDXREG(SISCR, 0x85, 0x88);
5442                        inSISIDXREG(SISCR, 0x85, reg);
5443                        outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5444                        outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5445                }
5446                if(ivideo->chip == XGI_40) {
5447                        outSISIDXREG(SISCR, 0x97, 0x00);
5448                }
5449                outSISIDXREG(SISCR, 0x98, 0x01);
5450                outSISIDXREG(SISCR, 0x9a, 0x02);
5451
5452                outSISIDXREG(SISSR, 0x18, 0x01);
5453                if((ivideo->chip == XGI_20) ||
5454                   (ivideo->revision_id == 2)) {
5455                        outSISIDXREG(SISSR, 0x19, 0x40);
5456                } else {
5457                        outSISIDXREG(SISSR, 0x19, 0x20);
5458                }
5459                outSISIDXREG(SISSR, 0x16, 0x00);
5460                outSISIDXREG(SISSR, 0x16, 0x80);
5461                if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5462                        sisfb_post_xgi_delay(ivideo, 0x43);
5463                        sisfb_post_xgi_delay(ivideo, 0x43);
5464                        sisfb_post_xgi_delay(ivideo, 0x43);
5465                        outSISIDXREG(SISSR, 0x18, 0x00);
5466                        if((ivideo->chip == XGI_20) ||
5467                           (ivideo->revision_id == 2)) {
5468                                outSISIDXREG(SISSR, 0x19, 0x40);
5469                        } else {
5470                                outSISIDXREG(SISSR, 0x19, 0x20);
5471                        }
5472                } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5473                        /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5474                }
5475                outSISIDXREG(SISSR, 0x16, 0x00);
5476                outSISIDXREG(SISSR, 0x16, 0x80);
5477                sisfb_post_xgi_delay(ivideo, 4);
5478                v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5479                if(ivideo->haveXGIROM) {
5480                        v1 = bios[0xf0];
5481                        index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5482                        v2 = bios[index];
5483                        v3 = bios[index + 1];
5484                        v4 = bios[index + 2];
5485                        v5 = bios[index + 3];
5486                }
5487                outSISIDXREG(SISSR, 0x18, v1);
5488                outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5489                outSISIDXREG(SISSR, 0x16, v2);
5490                outSISIDXREG(SISSR, 0x16, v3);
5491                sisfb_post_xgi_delay(ivideo, 0x43);
5492                outSISIDXREG(SISSR, 0x1b, 0x03);
5493                sisfb_post_xgi_delay(ivideo, 0x22);
5494                outSISIDXREG(SISSR, 0x18, v1);
5495                outSISIDXREG(SISSR, 0x19, 0x00);
5496                outSISIDXREG(SISSR, 0x16, v4);
5497                outSISIDXREG(SISSR, 0x16, v5);
5498                outSISIDXREG(SISSR, 0x1b, 0x00);
5499                break;
5500        case 1:
5501                outSISIDXREG(SISCR, 0x82, 0x77);
5502                outSISIDXREG(SISCR, 0x86, 0x00);
5503                inSISIDXREG(SISCR, 0x86, reg);
5504                outSISIDXREG(SISCR, 0x86, 0x88);
5505                inSISIDXREG(SISCR, 0x86, reg);
5506                v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5507                if(ivideo->haveXGIROM) {
5508                        v1 = bios[regb + 0x168];
5509                        v2 = bios[regb + 0x160];
5510                        v3 = bios[regb + 0x158];
5511                }
5512                outSISIDXREG(SISCR, 0x86, v1);
5513                outSISIDXREG(SISCR, 0x82, 0x77);
5514                outSISIDXREG(SISCR, 0x85, 0x00);
5515                inSISIDXREG(SISCR, 0x85, reg);
5516                outSISIDXREG(SISCR, 0x85, 0x88);
5517                inSISIDXREG(SISCR, 0x85, reg);
5518                outSISIDXREG(SISCR, 0x85, v2);
5519                outSISIDXREG(SISCR, 0x82, v3);
5520                outSISIDXREG(SISCR, 0x98, 0x01);
5521                outSISIDXREG(SISCR, 0x9a, 0x02);
5522
5523                outSISIDXREG(SISSR, 0x28, 0x64);
5524                outSISIDXREG(SISSR, 0x29, 0x63);
5525                sisfb_post_xgi_delay(ivideo, 15);
5526                outSISIDXREG(SISSR, 0x18, 0x00);
5527                outSISIDXREG(SISSR, 0x19, 0x20);
5528                outSISIDXREG(SISSR, 0x16, 0x00);
5529                outSISIDXREG(SISSR, 0x16, 0x80);
5530                outSISIDXREG(SISSR, 0x18, 0xc5);
5531                outSISIDXREG(SISSR, 0x19, 0x23);
5532                outSISIDXREG(SISSR, 0x16, 0x00);
5533                outSISIDXREG(SISSR, 0x16, 0x80);
5534                sisfb_post_xgi_delay(ivideo, 1);
5535                outSISIDXREG(SISCR, 0x97,0x11);
5536                sisfb_post_xgi_setclocks(ivideo, regb);
5537                sisfb_post_xgi_delay(ivideo, 0x46);
5538                outSISIDXREG(SISSR, 0x18, 0xc5);
5539                outSISIDXREG(SISSR, 0x19, 0x23);
5540                outSISIDXREG(SISSR, 0x16, 0x00);
5541                outSISIDXREG(SISSR, 0x16, 0x80);
5542                sisfb_post_xgi_delay(ivideo, 1);
5543                outSISIDXREG(SISSR, 0x1b, 0x04);
5544                sisfb_post_xgi_delay(ivideo, 1);
5545                outSISIDXREG(SISSR, 0x1b, 0x00);
5546                sisfb_post_xgi_delay(ivideo, 1);
5547                v1 = 0x31;
5548                if(ivideo->haveXGIROM) {
5549                        v1 = bios[0xf0];
5550                }
5551                outSISIDXREG(SISSR, 0x18, v1);
5552                outSISIDXREG(SISSR, 0x19, 0x06);
5553                outSISIDXREG(SISSR, 0x16, 0x04);
5554                outSISIDXREG(SISSR, 0x16, 0x84);
5555                sisfb_post_xgi_delay(ivideo, 1);
5556                break;
5557        default:
5558                sisfb_post_xgi_setclocks(ivideo, regb);
5559                if((ivideo->chip == XGI_40) &&
5560                   ((ivideo->revision_id == 1) ||
5561                    (ivideo->revision_id == 2))) {
5562                        outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5563                        outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5564                        outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5565                } else {
5566                        outSISIDXREG(SISCR, 0x82, 0x88);
5567                        outSISIDXREG(SISCR, 0x86, 0x00);
5568                        inSISIDXREG(SISCR, 0x86, reg);
5569                        outSISIDXREG(SISCR, 0x86, 0x88);
5570                        outSISIDXREG(SISCR, 0x82, 0x77);
5571                        outSISIDXREG(SISCR, 0x85, 0x00);
5572                        inSISIDXREG(SISCR, 0x85, reg);
5573                        outSISIDXREG(SISCR, 0x85, 0x88);
5574                        inSISIDXREG(SISCR, 0x85, reg);
5575                        v1 = cs160[regb]; v2 = cs158[regb];
5576                        if(ivideo->haveXGIROM) {
5577                                v1 = bios[regb + 0x160];
5578                                v2 = bios[regb + 0x158];
5579                        }
5580                        outSISIDXREG(SISCR, 0x85, v1);
5581                        outSISIDXREG(SISCR, 0x82, v2);
5582                }
5583                if(ivideo->chip == XGI_40) {
5584                        outSISIDXREG(SISCR, 0x97, 0x11);
5585                }
5586                if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5587                        outSISIDXREG(SISCR, 0x98, 0x01);
5588                } else {
5589                        outSISIDXREG(SISCR, 0x98, 0x03);
5590                }
5591                outSISIDXREG(SISCR, 0x9a, 0x02);
5592
5593                if(ivideo->chip == XGI_40) {
5594                        outSISIDXREG(SISSR, 0x18, 0x01);
5595                } else {
5596                        outSISIDXREG(SISSR, 0x18, 0x00);
5597                }
5598                outSISIDXREG(SISSR, 0x19, 0x40);
5599                outSISIDXREG(SISSR, 0x16, 0x00);
5600                outSISIDXREG(SISSR, 0x16, 0x80);
5601                if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5602                        sisfb_post_xgi_delay(ivideo, 0x43);
5603                        sisfb_post_xgi_delay(ivideo, 0x43);
5604                        sisfb_post_xgi_delay(ivideo, 0x43);
5605                        outSISIDXREG(SISSR, 0x18, 0x00);
5606                        outSISIDXREG(SISSR, 0x19, 0x40);
5607                        outSISIDXREG(SISSR, 0x16, 0x00);
5608                        outSISIDXREG(SISSR, 0x16, 0x80);
5609                }
5610                sisfb_post_xgi_delay(ivideo, 4);
5611                v1 = 0x31;
5612                if(ivideo->haveXGIROM) {
5613                        v1 = bios[0xf0];
5614                }
5615                outSISIDXREG(SISSR, 0x18, v1);
5616                outSISIDXREG(SISSR, 0x19, 0x01);
5617                if(ivideo->chip == XGI_40) {
5618                        outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5619                        outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5620                } else {
5621                        outSISIDXREG(SISSR, 0x16, 0x05);
5622                        outSISIDXREG(SISSR, 0x16, 0x85);
5623                }
5624                sisfb_post_xgi_delay(ivideo, 0x43);
5625                if(ivideo->chip == XGI_40) {
5626                        outSISIDXREG(SISSR, 0x1b, 0x01);
5627                } else {
5628                        outSISIDXREG(SISSR, 0x1b, 0x03);
5629                }
5630                sisfb_post_xgi_delay(ivideo, 0x22);
5631                outSISIDXREG(SISSR, 0x18, v1);
5632                outSISIDXREG(SISSR, 0x19, 0x00);
5633                if(ivideo->chip == XGI_40) {
5634                        outSISIDXREG(SISSR, 0x16, bios[0x540]);
5635                        outSISIDXREG(SISSR, 0x16, bios[0x541]);
5636                } else {
5637                        outSISIDXREG(SISSR, 0x16, 0x05);
5638                        outSISIDXREG(SISSR, 0x16, 0x85);
5639                }
5640                outSISIDXREG(SISSR, 0x1b, 0x00);
5641        }
5642
5643        regb = 0;        /* ! */
5644        v1 = 0x03;
5645        if(ivideo->haveXGIROM) {
5646                v1 = bios[0x110 + regb];
5647        }
5648        outSISIDXREG(SISSR, 0x1b, v1);
5649
5650        /* RAM size */
5651        v1 = 0x00; v2 = 0x00;
5652        if(ivideo->haveXGIROM) {
5653                v1 = bios[0x62];
5654                v2 = bios[0x63];
5655        }
5656        regb = 0;        /* ! */
5657        regd = 1 << regb;
5658        if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5659
5660                outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5661                outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5662
5663        } else {
5664
5665                /* Set default mode, don't clear screen */
5666                ivideo->SiS_Pr.SiS_UseOEM = false;
5667                SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5668                SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5669                ivideo->curFSTN = ivideo->curDSTN = 0;
5670                ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5671                SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5672
5673                outSISIDXREG(SISSR, 0x05, 0x86);
5674
5675                /* Disable read-cache */
5676                andSISIDXREG(SISSR, 0x21, 0xdf);
5677                sisfb_post_xgi_ramsize(ivideo);
5678                /* Enable read-cache */
5679                orSISIDXREG(SISSR, 0x21, 0x20);
5680
5681        }
5682
5683#if 0
5684        printk(KERN_DEBUG "-----------------\n");
5685        for(i = 0; i < 0xff; i++) {
5686                inSISIDXREG(SISCR, i, reg);
5687                printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5688        }
5689        for(i = 0; i < 0x40; i++) {
5690                inSISIDXREG(SISSR, i, reg);
5691                printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5692        }
5693        printk(KERN_DEBUG "-----------------\n");
5694#endif
5695
5696        /* Sense CRT1 */
5697        if(ivideo->chip == XGI_20) {
5698                orSISIDXREG(SISCR, 0x32, 0x20);
5699        } else {
5700                inSISIDXREG(SISPART4, 0x00, reg);
5701                if((reg == 1) || (reg == 2)) {
5702                        sisfb_sense_crt1(ivideo);
5703                } else {
5704                        orSISIDXREG(SISCR, 0x32, 0x20);
5705                }
5706        }
5707
5708        /* Set default mode, don't clear screen */
5709        ivideo->SiS_Pr.SiS_UseOEM = false;
5710        SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5711        SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5712        ivideo->curFSTN = ivideo->curDSTN = 0;
5713        SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5714
5715        outSISIDXREG(SISSR, 0x05, 0x86);
5716
5717        /* Display off */
5718        orSISIDXREG(SISSR, 0x01, 0x20);
5719
5720        /* Save mode number in CR34 */
5721        outSISIDXREG(SISCR, 0x34, 0x2e);
5722
5723        /* Let everyone know what the current mode is */
5724        ivideo->modeprechange = 0x2e;
5725
5726        if(ivideo->chip == XGI_40) {
5727                inSISIDXREG(SISCR, 0xca, reg);
5728                inSISIDXREG(SISCR, 0xcc, v1);
5729                if((reg & 0x10) && (!(v1 & 0x04))) {
5730                        printk(KERN_ERR
5731                                "sisfb: Please connect power to the card.\n");
5732                        return 0;
5733                }
5734        }
5735
5736        return 1;
5737}
5738#endif
5739
5740static int __devinit
5741sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5742{
5743        struct sisfb_chip_info        *chipinfo = &sisfb_chip_info[ent->driver_data];
5744        struct sis_video_info        *ivideo = NULL;
5745        struct fb_info                *sis_fb_info = NULL;
5746        u16 reg16;
5747        u8  reg;
5748        int i, ret;
5749
5750        if(sisfb_off)
5751                return -ENXIO;
5752
5753        sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5754        if(!sis_fb_info)
5755                return -ENOMEM;
5756
5757        ivideo = (struct sis_video_info *)sis_fb_info->par;
5758        ivideo->memyselfandi = sis_fb_info;
5759
5760        ivideo->sisfb_id = SISFB_ID;
5761
5762        if(card_list == NULL) {
5763                ivideo->cardnumber = 0;
5764        } else {
5765                struct sis_video_info *countvideo = card_list;
5766                ivideo->cardnumber = 1;
5767                while((countvideo = countvideo->next) != NULL)
5768                        ivideo->cardnumber++;
5769        }
5770
5771        strncpy(ivideo->myid, chipinfo->chip_name, 30);
5772
5773        ivideo->warncount = 0;
5774        ivideo->chip_id = pdev->device;
5775        ivideo->chip_vendor = pdev->vendor;
5776        ivideo->revision_id = pdev->revision;
5777        ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5778        pci_read_config_word(pdev, PCI_COMMAND, &reg16);
5779        ivideo->sisvga_enabled = reg16 & 0x01;
5780        ivideo->pcibus = pdev->bus->number;
5781        ivideo->pcislot = PCI_SLOT(pdev->devfn);
5782        ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5783        ivideo->subsysvendor = pdev->subsystem_vendor;
5784        ivideo->subsysdevice = pdev->subsystem_device;
5785
5786#ifndef MODULE
5787        if(sisfb_mode_idx == -1) {
5788                sisfb_get_vga_mode_from_kernel();
5789        }
5790#endif
5791
5792        ivideo->chip = chipinfo->chip;
5793        ivideo->sisvga_engine = chipinfo->vgaengine;
5794        ivideo->hwcursor_size = chipinfo->hwcursor_size;
5795        ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5796        ivideo->mni = chipinfo->mni;
5797
5798        ivideo->detectedpdc  = 0xff;
5799        ivideo->detectedpdca = 0xff;
5800        ivideo->detectedlcda = 0xff;
5801
5802        ivideo->sisfb_thismonitor.datavalid = false;
5803
5804        ivideo->current_base = 0;
5805
5806        ivideo->engineok = 0;
5807
5808        ivideo->sisfb_was_boot_device = 0;
5809
5810        if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5811                if(ivideo->sisvga_enabled)
5812                        ivideo->sisfb_was_boot_device = 1;
5813                else {
5814                        printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5815                                "but marked as boot video device ???\n");
5816                        printk(KERN_DEBUG "sisfb: I will not accept this "
5817                                "as the primary VGA device\n");
5818                }
5819        }
5820
5821        ivideo->sisfb_parm_mem = sisfb_parm_mem;
5822        ivideo->sisfb_accel = sisfb_accel;
5823        ivideo->sisfb_ypan = sisfb_ypan;
5824        ivideo->sisfb_max = sisfb_max;
5825        ivideo->sisfb_userom = sisfb_userom;
5826        ivideo->sisfb_useoem = sisfb_useoem;
5827        ivideo->sisfb_mode_idx = sisfb_mode_idx;
5828        ivideo->sisfb_parm_rate = sisfb_parm_rate;
5829        ivideo->sisfb_crt1off = sisfb_crt1off;
5830        ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5831        ivideo->sisfb_crt2type = sisfb_crt2type;
5832        ivideo->sisfb_crt2flags = sisfb_crt2flags;
5833        /* pdc(a), scalelcd, special timing, lvdshl handled below */
5834        ivideo->sisfb_dstn = sisfb_dstn;
5835        ivideo->sisfb_fstn = sisfb_fstn;
5836        ivideo->sisfb_tvplug = sisfb_tvplug;
5837        ivideo->sisfb_tvstd = sisfb_tvstd;
5838        ivideo->tvxpos = sisfb_tvxposoffset;
5839        ivideo->tvypos = sisfb_tvyposoffset;
5840        ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5841        ivideo->refresh_rate = 0;
5842        if(ivideo->sisfb_parm_rate != -1) {
5843                ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5844        }
5845
5846        ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5847        ivideo->SiS_Pr.CenterScreen = -1;
5848        ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5849        ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5850
5851        ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5852        ivideo->SiS_Pr.SiS_CHOverScan = -1;
5853        ivideo->SiS_Pr.SiS_ChSW = false;
5854        ivideo->SiS_Pr.SiS_UseLCDA = false;
5855        ivideo->SiS_Pr.HaveEMI = false;
5856        ivideo->SiS_Pr.HaveEMILCD = false;
5857        ivideo->SiS_Pr.OverruleEMI = false;
5858        ivideo->SiS_Pr.SiS_SensibleSR11 = false;
5859        ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5860        ivideo->SiS_Pr.PDC  = -1;
5861        ivideo->SiS_Pr.PDCA = -1;
5862        ivideo->SiS_Pr.DDCPortMixup = false;
5863#ifdef CONFIG_FB_SIS_315
5864        if(ivideo->chip >= SIS_330) {
5865                ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5866                if(ivideo->chip >= SIS_661) {
5867                        ivideo->SiS_Pr.SiS_SensibleSR11 = true;
5868                }
5869        }
5870#endif
5871
5872        memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5873
5874        pci_set_drvdata(pdev, ivideo);
5875
5876        /* Patch special cases */
5877        if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5878                switch(ivideo->nbridge->device) {
5879#ifdef CONFIG_FB_SIS_300
5880                case PCI_DEVICE_ID_SI_730:
5881                        ivideo->chip = SIS_730;
5882                        strcpy(ivideo->myid, "SiS 730");
5883                        break;
5884#endif
5885#ifdef CONFIG_FB_SIS_315
5886                case PCI_DEVICE_ID_SI_651:
5887                        /* ivideo->chip is ok */
5888                        strcpy(ivideo->myid, "SiS 651");
5889                        break;
5890                case PCI_DEVICE_ID_SI_740:
5891                        ivideo->chip = SIS_740;
5892                        strcpy(ivideo->myid, "SiS 740");
5893                        break;
5894                case PCI_DEVICE_ID_SI_661:
5895                        ivideo->chip = SIS_661;
5896                        strcpy(ivideo->myid, "SiS 661");
5897                        break;
5898                case PCI_DEVICE_ID_SI_741:
5899                        ivideo->chip = SIS_741;
5900                        strcpy(ivideo->myid, "SiS 741");
5901                        break;
5902                case PCI_DEVICE_ID_SI_760:
5903                        ivideo->chip = SIS_760;
5904                        strcpy(ivideo->myid, "SiS 760");
5905                        break;
5906                case PCI_DEVICE_ID_SI_761:
5907                        ivideo->chip = SIS_761;
5908                        strcpy(ivideo->myid, "SiS 761");
5909                        break;
5910#endif
5911                default:
5912                        break;
5913                }
5914        }
5915
5916        ivideo->SiS_Pr.ChipType = ivideo->chip;
5917
5918        ivideo->SiS_Pr.ivideo = (void *)ivideo;
5919
5920#ifdef CONFIG_FB_SIS_315
5921        if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5922           (ivideo->SiS_Pr.ChipType == SIS_315)) {
5923                ivideo->SiS_Pr.ChipType = SIS_315H;
5924        }
5925#endif
5926
5927        if(!ivideo->sisvga_enabled) {
5928                if(pci_enable_device(pdev)) {
5929                        if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
5930                        pci_set_drvdata(pdev, NULL);
5931                        kfree(sis_fb_info);
5932                        return -EIO;
5933                }
5934        }
5935
5936        ivideo->video_base = pci_resource_start(pdev, 0);
5937        ivideo->mmio_base  = pci_resource_start(pdev, 1);
5938        ivideo->mmio_size  = pci_resource_len(pdev, 1);
5939        ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
5940        ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
5941
5942        SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
5943
5944#ifdef CONFIG_FB_SIS_300
5945        /* Find PCI systems for Chrontel/GPIO communication setup */
5946        if(ivideo->chip == SIS_630) {
5947                i = 0;
5948                do {
5949                        if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5950                           mychswtable[i].subsysCard   == ivideo->subsysdevice) {
5951                                ivideo->SiS_Pr.SiS_ChSW = true;
5952                                printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5953                                        "requiring Chrontel/GPIO setup\n",
5954                                        mychswtable[i].vendorName,
5955                                        mychswtable[i].cardName);
5956                                ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
5957                                break;
5958                        }
5959                        i++;
5960                } while(mychswtable[i].subsysVendor != 0);
5961        }
5962#endif
5963
5964#ifdef CONFIG_FB_SIS_315
5965        if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
5966                ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
5967        }
5968#endif
5969
5970        outSISIDXREG(SISSR, 0x05, 0x86);
5971
5972        if( (!ivideo->sisvga_enabled)
5973#if !defined(__i386__) && !defined(__x86_64__)
5974                              || (sisfb_resetcard)
5975#endif
5976                                                   ) {
5977                for(i = 0x30; i <= 0x3f; i++) {
5978                        outSISIDXREG(SISCR, i, 0x00);
5979                }
5980        }
5981
5982        /* Find out about current video mode */
5983        ivideo->modeprechange = 0x03;
5984        inSISIDXREG(SISCR, 0x34, reg);
5985        if(reg & 0x7f) {
5986                ivideo->modeprechange = reg & 0x7f;
5987        } else if(ivideo->sisvga_enabled) {
5988#if defined(__i386__) || defined(__x86_64__)
5989                unsigned char __iomem *tt = ioremap(0x400, 0x100);
5990                if(tt) {
5991                        ivideo->modeprechange = readb(tt + 0x49);
5992                        iounmap(tt);
5993                }
5994#endif
5995        }
5996
5997        /* Search and copy ROM image */
5998        ivideo->bios_abase = NULL;
5999        ivideo->SiS_Pr.VirtualRomBase = NULL;
6000        ivideo->SiS_Pr.UseROM = false;
6001        ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
6002        if(ivideo->sisfb_userom) {
6003                ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6004                ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6005                ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
6006                printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6007                        ivideo->SiS_Pr.UseROM ? "" : "not ");
6008                if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6009                   ivideo->SiS_Pr.UseROM = false;
6010                   ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
6011                   if( (ivideo->revision_id == 2) &&
6012                       (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6013                        ivideo->SiS_Pr.DDCPortMixup = true;
6014                   }
6015                }
6016        } else {
6017                printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6018        }
6019
6020        /* Find systems for special custom timing */
6021        if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6022                sisfb_detect_custom_timing(ivideo);
6023        }
6024
6025        /* POST card in case this has not been done by the BIOS */
6026        if( (!ivideo->sisvga_enabled)
6027#if !defined(__i386__) && !defined(__x86_64__)
6028                             || (sisfb_resetcard)
6029#endif
6030                                                 ) {
6031#ifdef CONFIG_FB_SIS_300
6032                if(ivideo->sisvga_engine == SIS_300_VGA) {
6033                        if(ivideo->chip == SIS_300) {
6034                                sisfb_post_sis300(pdev);
6035                                ivideo->sisfb_can_post = 1;
6036                        }
6037                }
6038#endif
6039
6040#ifdef CONFIG_FB_SIS_315
6041                if(ivideo->sisvga_engine == SIS_315_VGA) {
6042                        int result = 1;
6043                /*        if((ivideo->chip == SIS_315H)   ||
6044                           (ivideo->chip == SIS_315)    ||
6045                           (ivideo->chip == SIS_315PRO) ||
6046                           (ivideo->chip == SIS_330)) {
6047                                sisfb_post_sis315330(pdev);
6048                        } else */ if(ivideo->chip == XGI_20) {
6049                                result = sisfb_post_xgi(pdev);
6050                                ivideo->sisfb_can_post = 1;
6051                        } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6052                                result = sisfb_post_xgi(pdev);
6053                                ivideo->sisfb_can_post = 1;
6054                        } else {
6055                                printk(KERN_INFO "sisfb: Card is not "
6056                                        "POSTed and sisfb can't do this either.\n");
6057                        }
6058                        if(!result) {
6059                                printk(KERN_ERR "sisfb: Failed to POST card\n");
6060                                ret = -ENODEV;
6061                                goto error_3;
6062                        }
6063                }
6064#endif
6065        }
6066
6067        ivideo->sisfb_card_posted = 1;
6068
6069        /* Find out about RAM size */
6070        if(sisfb_get_dram_size(ivideo)) {
6071                printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6072                ret = -ENODEV;
6073                goto error_3;
6074        }
6075
6076
6077        /* Enable PCI addressing and MMIO */
6078        if((ivideo->sisfb_mode_idx < 0) ||
6079           ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6080                /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
6081                orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6082                /* Enable 2D accelerator engine */
6083                orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6084        }
6085
6086        if(sisfb_pdc != 0xff) {
6087                if(ivideo->sisvga_engine == SIS_300_VGA)
6088                        sisfb_pdc &= 0x3c;
6089                else
6090                        sisfb_pdc &= 0x1f;
6091                ivideo->SiS_Pr.PDC = sisfb_pdc;
6092        }
6093#ifdef CONFIG_FB_SIS_315
6094        if(ivideo->sisvga_engine == SIS_315_VGA) {
6095                if(sisfb_pdca != 0xff)
6096                        ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6097        }
6098#endif
6099
6100        if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6101                printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6102                                (int)(ivideo->video_size >> 20));
6103                printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6104                ret = -ENODEV;
6105                goto error_3;
6106        }
6107
6108        if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6109                printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6110                ret = -ENODEV;
6111                goto error_2;
6112        }
6113
6114        ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6115        ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6116        if(!ivideo->video_vbase) {
6117                printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6118                ret = -ENODEV;
6119                goto error_1;
6120        }
6121
6122        ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6123        if(!ivideo->mmio_vbase) {
6124                printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6125                ret = -ENODEV;
6126error_0:        iounmap(ivideo->video_vbase);
6127error_1:        release_mem_region(ivideo->video_base, ivideo->video_size);
6128error_2:        release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6129error_3:        vfree(ivideo->bios_abase);
6130                if(ivideo->lpcdev)
6131                        pci_dev_put(ivideo->lpcdev);
6132                if(ivideo->nbridge)
6133                        pci_dev_put(ivideo->nbridge);
6134                pci_set_drvdata(pdev, NULL);
6135                if(!ivideo->sisvga_enabled)
6136                        pci_disable_device(pdev);
6137                kfree(sis_fb_info);
6138                return ret;
6139        }
6140
6141        printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6142                ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6143
6144        if(ivideo->video_offset) {
6145                printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6146                        ivideo->video_offset / 1024);
6147        }
6148
6149        printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6150                ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6151
6152
6153        /* Determine the size of the command queue */
6154        if(ivideo->sisvga_engine == SIS_300_VGA) {
6155                ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6156        } else {
6157                if(ivideo->chip == XGI_20) {
6158                        ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6159                } else {
6160                        ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6161                }
6162        }
6163
6164        /* Engines are no longer initialized here; this is
6165         * now done after the first mode-switch (if the
6166         * submitted var has its acceleration flags set).
6167         */
6168
6169        /* Calculate the base of the (unused) hw cursor */
6170        ivideo->hwcursor_vbase = ivideo->video_vbase
6171                                 + ivideo->video_size
6172                                 - ivideo->cmdQueueSize
6173                                 - ivideo->hwcursor_size;
6174        ivideo->caps |= HW_CURSOR_CAP;
6175
6176        /* Initialize offscreen memory manager */
6177        if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6178                printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6179        }
6180
6181        /* Used for clearing the screen only, therefore respect our mem limit */
6182        ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6183        ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6184
6185        ivideo->mtrr = -1;
6186
6187        ivideo->vbflags = 0;
6188        ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6189        ivideo->tvdefmodeidx  = DEFAULT_TVMODE;
6190        ivideo->defmodeidx    = DEFAULT_MODE;
6191
6192        ivideo->newrom = 0;
6193        if(ivideo->chip < XGI_20) {
6194                if(ivideo->bios_abase) {
6195                        ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6196                }
6197        }
6198
6199        if((ivideo->sisfb_mode_idx < 0) ||
6200           ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6201
6202                sisfb_sense_crt1(ivideo);
6203
6204                sisfb_get_VB_type(ivideo);
6205
6206                if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6207                        sisfb_detect_VB_connect(ivideo);
6208                }
6209
6210                ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6211
6212                /* Decide on which CRT2 device to use */
6213                if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6214                        if(ivideo->sisfb_crt2type != -1) {
6215                                if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6216                                   (ivideo->vbflags & CRT2_LCD)) {
6217                                        ivideo->currentvbflags |= CRT2_LCD;
6218                                } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6219                                        ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6220                                }
6221                        } else {
6222                                /* Chrontel 700x TV detection often unreliable, therefore
6223                                 * use a different default order on such machines
6224                                 */
6225                                if((ivideo->sisvga_engine == SIS_300_VGA) &&
6226                                   (ivideo->vbflags2 & VB2_CHRONTEL)) {
6227                                        if(ivideo->vbflags & CRT2_LCD)
6228                                                ivideo->currentvbflags |= CRT2_LCD;
6229                                        else if(ivideo->vbflags & CRT2_TV)
6230                                                ivideo->currentvbflags |= CRT2_TV;
6231                                        else if(ivideo->vbflags & CRT2_VGA)
6232                                                ivideo->currentvbflags |= CRT2_VGA;
6233                                } else {
6234                                        if(ivideo->vbflags & CRT2_TV)
6235                                                ivideo->currentvbflags |= CRT2_TV;
6236                                        else if(ivideo->vbflags & CRT2_LCD)
6237                                                ivideo->currentvbflags |= CRT2_LCD;
6238                                        else if(ivideo->vbflags & CRT2_VGA)
6239                                                ivideo->currentvbflags |= CRT2_VGA;
6240                                }
6241                        }
6242                }
6243
6244                if(ivideo->vbflags & CRT2_LCD) {
6245                        sisfb_detect_lcd_type(ivideo);
6246                }
6247
6248                sisfb_save_pdc_emi(ivideo);
6249
6250                if(!ivideo->sisfb_crt1off) {
6251                        sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6252                } else {
6253                        if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6254                           (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6255                                sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6256                        }
6257                }
6258
6259                if(ivideo->sisfb_mode_idx >= 0) {
6260                        int bu = ivideo->sisfb_mode_idx;
6261                        ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6262                                        ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6263                        if(bu != ivideo->sisfb_mode_idx) {
6264                                printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6265                                        sisbios_mode[bu].xres,
6266                                        sisbios_mode[bu].yres,
6267                                        sisbios_mode[bu].bpp);
6268                        }
6269                }
6270
6271                if(ivideo->sisfb_mode_idx < 0) {
6272                        switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6273                           case CRT2_LCD:
6274                                ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6275                                break;
6276                           case CRT2_TV:
6277                                ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6278                                break;
6279                           default:
6280                                ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6281                                break;
6282                        }
6283                }
6284
6285                ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6286
6287                if(ivideo->refresh_rate != 0) {
6288                        sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6289                                                ivideo->sisfb_mode_idx);
6290                }
6291
6292                if(ivideo->rate_idx == 0) {
6293                        ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6294                        ivideo->refresh_rate = 60;
6295                }
6296
6297                if(ivideo->sisfb_thismonitor.datavalid) {
6298                        if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6299                                                ivideo->sisfb_mode_idx,
6300                                                ivideo->rate_idx,
6301                                                ivideo->refresh_rate)) {
6302                                printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6303                                                        "exceeds monitor specs!\n");
6304                        }
6305                }
6306
6307                ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6308                ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6309                ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6310
6311                sisfb_set_vparms(ivideo);
6312
6313                printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6314                        ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6315                        ivideo->refresh_rate);
6316
6317                /* Set up the default var according to chosen default display mode */
6318                ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6319                ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6320                ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6321
6322                sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6323
6324                ivideo->default_var.pixclock = (u32) (1000000000 /
6325                        sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6326
6327                if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6328                                                ivideo->rate_idx, &ivideo->default_var)) {
6329                        if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6330                                ivideo->default_var.pixclock <<= 1;
6331                        }
6332                }
6333
6334                if(ivideo->sisfb_ypan) {
6335                        /* Maximize regardless of sisfb_max at startup */
6336                        ivideo->default_var.yres_virtual =
6337                                sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6338                        if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6339                                ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6340                        }
6341                }
6342
6343                sisfb_calc_pitch(ivideo, &ivideo->default_var);
6344
6345                ivideo->accel = 0;
6346                if(ivideo->sisfb_accel) {
6347                        ivideo->accel = -1;
6348#ifdef STUPID_ACCELF_TEXT_SHIT
6349                        ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6350#endif
6351                }
6352                sisfb_initaccel(ivideo);
6353
6354#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6355                sis_fb_info->flags = FBINFO_DEFAULT                 |
6356                                     FBINFO_HWACCEL_YPAN         |
6357                                     FBINFO_HWACCEL_XPAN         |
6358                                     FBINFO_HWACCEL_COPYAREA         |
6359                                     FBINFO_HWACCEL_FILLRECT         |
6360                                     ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6361#else
6362                sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6363#endif
6364                sis_fb_info->var = ivideo->default_var;
6365                sis_fb_info->fix = ivideo->sisfb_fix;
6366                sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6367                sis_fb_info->fbops = &sisfb_ops;
6368                sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6369                sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6370
6371                fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6372
6373                printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6374
6375#ifdef CONFIG_MTRR
6376                ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6377                                        MTRR_TYPE_WRCOMB, 1);
6378                if(ivideo->mtrr < 0) {
6379                        printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6380                }
6381#endif
6382
6383                if(register_framebuffer(sis_fb_info) < 0) {
6384                        printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6385                        ret = -EINVAL;
6386                        iounmap(ivideo->mmio_vbase);
6387                        goto error_0;
6388                }
6389
6390                ivideo->registered = 1;
6391
6392                /* Enlist us */
6393                ivideo->next = card_list;
6394                card_list = ivideo;
6395
6396                printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6397                        ivideo->sisfb_accel ? "enabled" : "disabled",
6398                        ivideo->sisfb_ypan  ?
6399                                (ivideo->sisfb_max ? "enabled (auto-max)" :
6400                                                "enabled (no auto-max)") :
6401                                                                        "disabled");
6402
6403
6404                printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6405                        sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6406
6407                printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6408
6409        }        /* if mode = "none" */
6410
6411        return 0;
6412}
6413
6414/*****************************************************/
6415/*                PCI DEVICE HANDLING                */
6416/*****************************************************/
6417
6418static void __devexit sisfb_remove(struct pci_dev *pdev)
6419{
6420        struct sis_video_info        *ivideo = pci_get_drvdata(pdev);
6421        struct fb_info                *sis_fb_info = ivideo->memyselfandi;
6422        int                        registered = ivideo->registered;
6423        int                        modechanged = ivideo->modechanged;
6424
6425        /* Unmap */
6426        iounmap(ivideo->mmio_vbase);
6427        iounmap(ivideo->video_vbase);
6428
6429        /* Release mem regions */
6430        release_mem_region(ivideo->video_base, ivideo->video_size);
6431        release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6432
6433        vfree(ivideo->bios_abase);
6434
6435        if(ivideo->lpcdev)
6436                pci_dev_put(ivideo->lpcdev);
6437
6438        if(ivideo->nbridge)
6439                pci_dev_put(ivideo->nbridge);
6440
6441#ifdef CONFIG_MTRR
6442        /* Release MTRR region */
6443        if(ivideo->mtrr >= 0)
6444                mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6445#endif
6446
6447        pci_set_drvdata(pdev, NULL);
6448
6449        /* If device was disabled when starting, disable
6450         * it when quitting.
6451         */
6452        if(!ivideo->sisvga_enabled)
6453                pci_disable_device(pdev);
6454
6455        /* Unregister the framebuffer */
6456        if(ivideo->registered) {
6457                unregister_framebuffer(sis_fb_info);
6458                framebuffer_release(sis_fb_info);
6459        }
6460
6461        /* OK, our ivideo is gone for good from here. */
6462
6463        /* TODO: Restore the initial mode
6464         * This sounds easy but is as good as impossible
6465         * on many machines with SiS chip and video bridge
6466         * since text modes are always set up differently
6467         * from machine to machine. Depends on the type
6468         * of integration between chipset and bridge.
6469         */
6470        if(registered && modechanged)
6471                printk(KERN_INFO
6472                        "sisfb: Restoring of text mode not supported yet\n");
6473};
6474
6475static struct pci_driver sisfb_driver = {
6476        .name                = "sisfb",
6477        .id_table         = sisfb_pci_table,
6478        .probe                = sisfb_probe,
6479        .remove         = __devexit_p(sisfb_remove)
6480};
6481
6482static int __init sisfb_init(void)
6483{
6484#ifndef MODULE
6485        char *options = NULL;
6486
6487        if(fb_get_options("sisfb", &options))
6488                return -ENODEV;
6489
6490        sisfb_setup(options);
6491#endif
6492        return pci_register_driver(&sisfb_driver);
6493}
6494
6495#ifndef MODULE
6496module_init(sisfb_init);
6497#endif
6498
6499/*****************************************************/
6500/*                      MODULE                       */
6501/*****************************************************/
6502
6503#ifdef MODULE
6504
6505static char                *mode = NULL;
6506static int                vesa = -1;
6507static unsigned int        rate = 0;
6508static unsigned int        crt1off = 1;
6509static unsigned int        mem = 0;
6510static char                *forcecrt2type = NULL;
6511static int                forcecrt1 = -1;
6512static int                pdc = -1;
6513static int                pdc1 = -1;
6514static int                noaccel = -1;
6515static int                noypan  = -1;
6516static int                nomax = -1;
6517static int                userom = -1;
6518static int                useoem = -1;
6519static char                *tvstandard = NULL;
6520static int                nocrt2rate = 0;
6521static int                scalelcd = -1;
6522static char                *specialtiming = NULL;
6523static int                lvdshl = -1;
6524static int                tvxposoffset = 0, tvyposoffset = 0;
6525#if !defined(__i386__) && !defined(__x86_64__)
6526static int                resetcard = 0;
6527static int                videoram = 0;
6528#endif
6529
6530static int __init sisfb_init_module(void)
6531{
6532        sisfb_setdefaultparms();
6533
6534        if(rate)
6535                sisfb_parm_rate = rate;
6536
6537        if((scalelcd == 0) || (scalelcd == 1))
6538                sisfb_scalelcd = scalelcd ^ 1;
6539
6540        /* Need to check crt2 type first for fstn/dstn */
6541
6542        if(forcecrt2type)
6543                sisfb_search_crt2type(forcecrt2type);
6544
6545        if(tvstandard)
6546                sisfb_search_tvstd(tvstandard);
6547
6548        if(mode)
6549                sisfb_search_mode(mode, false);
6550        else if(vesa != -1)
6551                sisfb_search_vesamode(vesa, false);
6552
6553        sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6554
6555        sisfb_forcecrt1 = forcecrt1;
6556        if(forcecrt1 == 1)
6557                sisfb_crt1off = 0;
6558        else if(forcecrt1 == 0)
6559                sisfb_crt1off = 1;
6560
6561        if(noaccel == 1)
6562                sisfb_accel = 0;
6563        else if(noaccel == 0)
6564                sisfb_accel = 1;
6565
6566        if(noypan == 1)
6567                sisfb_ypan = 0;
6568        else if(noypan == 0)
6569                sisfb_ypan = 1;
6570
6571        if(nomax == 1)
6572                sisfb_max = 0;
6573        else if(nomax == 0)
6574                sisfb_max = 1;
6575
6576        if(mem)
6577                sisfb_parm_mem = mem;
6578
6579        if(userom != -1)
6580                sisfb_userom = userom;
6581
6582        if(useoem != -1)
6583                sisfb_useoem = useoem;
6584
6585        if(pdc != -1)
6586                sisfb_pdc  = (pdc  & 0x7f);
6587
6588        if(pdc1 != -1)
6589                sisfb_pdca = (pdc1 & 0x1f);
6590
6591        sisfb_nocrt2rate = nocrt2rate;
6592
6593        if(specialtiming)
6594                sisfb_search_specialtiming(specialtiming);
6595
6596        if((lvdshl >= 0) && (lvdshl <= 3))
6597                sisfb_lvdshl = lvdshl;
6598
6599        sisfb_tvxposoffset = tvxposoffset;
6600        sisfb_tvyposoffset = tvyposoffset;
6601
6602#if !defined(__i386__) && !defined(__x86_64__)
6603        sisfb_resetcard = (resetcard) ? 1 : 0;
6604        if(videoram)
6605                sisfb_videoram = videoram;
6606#endif
6607
6608        return sisfb_init();
6609}
6610
6611static void __exit sisfb_remove_module(void)
6612{
6613        pci_unregister_driver(&sisfb_driver);
6614        printk(KERN_DEBUG "sisfb: Module unloaded\n");
6615}
6616
6617module_init(sisfb_init_module);
6618module_exit(sisfb_remove_module);
6619
6620MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6621MODULE_LICENSE("GPL");
6622MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6623
6624module_param(mem, int, 0);
6625module_param(noaccel, int, 0);
6626module_param(noypan, int, 0);
6627module_param(nomax, int, 0);
6628module_param(userom, int, 0);
6629module_param(useoem, int, 0);
6630module_param(mode, charp, 0);
6631module_param(vesa, int, 0);
6632module_param(rate, int, 0);
6633module_param(forcecrt1, int, 0);
6634module_param(forcecrt2type, charp, 0);
6635module_param(scalelcd, int, 0);
6636module_param(pdc, int, 0);
6637module_param(pdc1, int, 0);
6638module_param(specialtiming, charp, 0);
6639module_param(lvdshl, int, 0);
6640module_param(tvstandard, charp, 0);
6641module_param(tvxposoffset, int, 0);
6642module_param(tvyposoffset, int, 0);
6643module_param(nocrt2rate, int, 0);
6644#if !defined(__i386__) && !defined(__x86_64__)
6645module_param(resetcard, int, 0);
6646module_param(videoram, int, 0);
6647#endif
6648
6649MODULE_PARM_DESC(mem,
6650        "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6651          "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6652          "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6653          "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6654          "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6655          "The value is to be specified without 'KB'.\n");
6656
6657MODULE_PARM_DESC(noaccel,
6658        "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6659          "(default: 0)\n");
6660
6661MODULE_PARM_DESC(noypan,
6662        "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6663          "will be performed by redrawing the screen. (default: 0)\n");
6664
6665MODULE_PARM_DESC(nomax,
6666        "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
6667          "memory for the virtual screen in order to optimize scrolling performance. If\n"
6668          "this is set to anything other than 0, sisfb will not do this and thereby \n"
6669          "enable the user to positively specify a virtual Y size of the screen using\n"
6670          "fbset. (default: 0)\n");
6671
6672MODULE_PARM_DESC(mode,
6673        "\nSelects the desired default display mode in the format XxYxDepth,\n"
6674         "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
6675         "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6676         "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6677
6678MODULE_PARM_DESC(vesa,
6679        "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6680         "0x117 (default: 0x0103)\n");
6681
6682MODULE_PARM_DESC(rate,
6683        "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6684          "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6685          "will be ignored (default: 60)\n");
6686
6687MODULE_PARM_DESC(forcecrt1,
6688        "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6689          "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6690          "0=CRT1 OFF) (default: [autodetected])\n");
6691
6692MODULE_PARM_DESC(forcecrt2type,
6693        "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6694          "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6695          "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6696          "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6697          "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6698          "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6699          "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6700          "depends on the very hardware in use. (default: [autodetected])\n");
6701
6702MODULE_PARM_DESC(scalelcd,
6703        "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6704          "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6705          "show black bars around the image, TMDS panels will probably do the scaling\n"
6706          "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6707
6708MODULE_PARM_DESC(pdc,
6709        "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
6710          "should detect this correctly in most cases; however, sometimes this is not\n"
6711          "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
6712          "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6713          "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6714          "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
6715
6716#ifdef CONFIG_FB_SIS_315
6717MODULE_PARM_DESC(pdc1,
6718        "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
6719          "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6720          "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6721          "implemented yet.\n");
6722#endif
6723
6724MODULE_PARM_DESC(specialtiming,
6725        "\nPlease refer to documentation for more information on this option.\n");
6726
6727MODULE_PARM_DESC(lvdshl,
6728        "\nPlease refer to documentation for more information on this option.\n");
6729
6730MODULE_PARM_DESC(tvstandard,
6731        "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6732          "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6733
6734MODULE_PARM_DESC(tvxposoffset,
6735        "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6736          "Default: 0\n");
6737
6738MODULE_PARM_DESC(tvyposoffset,
6739        "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6740          "Default: 0\n");
6741
6742MODULE_PARM_DESC(nocrt2rate,
6743        "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6744          "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6745
6746#if !defined(__i386__) && !defined(__x86_64__)
6747#ifdef CONFIG_FB_SIS_300
6748MODULE_PARM_DESC(resetcard,
6749        "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
6750          "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6751          "currently). Default: 0\n");
6752
6753MODULE_PARM_DESC(videoram,
6754        "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6755          "some non-x86 architectures where the memory auto detection fails. Only\n"
6756          "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
6757#endif
6758#endif
6759
6760#endif            /*  /MODULE  */
6761
6762/* _GPL only for new symbols. */
6763EXPORT_SYMBOL(sis_malloc);
6764EXPORT_SYMBOL(sis_free);
6765EXPORT_SYMBOL_GPL(sis_malloc_new);
6766EXPORT_SYMBOL_GPL(sis_free_new);
6767
6768
6769