linux/drivers/video/sis/sis_main.c
<<
>>
Prefs
   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((sisfb_vrate[i].idx != 1) &&
 702                                                ((rate - sisfb_vrate[i-1].refresh) <= 2)) {
 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 = 8;
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        mutex_lock(&info->mm_lock);
1851        fix->smem_start  = ivideo->video_base + ivideo->video_offset;
1852        fix->smem_len    = ivideo->sisfb_mem;
1853        mutex_unlock(&info->mm_lock);
1854        fix->type        = FB_TYPE_PACKED_PIXELS;
1855        fix->type_aux    = 0;
1856        fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1857        fix->xpanstep    = 1;
1858        fix->ypanstep    = (ivideo->sisfb_ypan) ? 1 : 0;
1859        fix->ywrapstep   = 0;
1860        fix->line_length = ivideo->video_linelength;
1861        fix->mmio_start  = ivideo->mmio_base;
1862        fix->mmio_len    = ivideo->mmio_size;
1863        if(ivideo->sisvga_engine == SIS_300_VGA) {
1864                fix->accel = FB_ACCEL_SIS_GLAMOUR;
1865        } else if((ivideo->chip == SIS_330) ||
1866                  (ivideo->chip == SIS_760) ||
1867                  (ivideo->chip == SIS_761)) {
1868                fix->accel = FB_ACCEL_SIS_XABRE;
1869        } else if(ivideo->chip == XGI_20) {
1870                fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1871        } else if(ivideo->chip >= XGI_40) {
1872                fix->accel = FB_ACCEL_XGI_VOLARI_V;
1873        } else {
1874                fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1875        }
1876
1877        return 0;
1878}
1879
1880/* ----------------  fb_ops structures ----------------- */
1881
1882static struct fb_ops sisfb_ops = {
1883        .owner          = THIS_MODULE,
1884        .fb_open        = sisfb_open,
1885        .fb_release     = sisfb_release,
1886        .fb_check_var   = sisfb_check_var,
1887        .fb_set_par     = sisfb_set_par,
1888        .fb_setcolreg   = sisfb_setcolreg,
1889        .fb_pan_display = sisfb_pan_display,
1890        .fb_blank       = sisfb_blank,
1891        .fb_fillrect    = fbcon_sis_fillrect,
1892        .fb_copyarea    = fbcon_sis_copyarea,
1893        .fb_imageblit   = cfb_imageblit,
1894#ifdef CONFIG_FB_SOFT_CURSOR
1895        .fb_cursor      = soft_cursor,
1896#endif
1897        .fb_sync        = fbcon_sis_sync,
1898#ifdef SIS_NEW_CONFIG_COMPAT
1899        .fb_compat_ioctl= sisfb_ioctl,
1900#endif
1901        .fb_ioctl       = sisfb_ioctl
1902};
1903
1904/* ---------------- Chip generation dependent routines ---------------- */
1905
1906static struct pci_dev * __devinit
1907sisfb_get_northbridge(int basechipid)
1908{
1909        struct pci_dev *pdev = NULL;
1910        int nbridgenum, nbridgeidx, i;
1911        static const unsigned short nbridgeids[] = {
1912                PCI_DEVICE_ID_SI_540,   /* for SiS 540 VGA */
1913                PCI_DEVICE_ID_SI_630,   /* for SiS 630/730 VGA */
1914                PCI_DEVICE_ID_SI_730,
1915                PCI_DEVICE_ID_SI_550,   /* for SiS 550 VGA */
1916                PCI_DEVICE_ID_SI_650,   /* for SiS 650/651/740 VGA */
1917                PCI_DEVICE_ID_SI_651,
1918                PCI_DEVICE_ID_SI_740,
1919                PCI_DEVICE_ID_SI_661,   /* for SiS 661/741/660/760/761 VGA */
1920                PCI_DEVICE_ID_SI_741,
1921                PCI_DEVICE_ID_SI_660,
1922                PCI_DEVICE_ID_SI_760,
1923                PCI_DEVICE_ID_SI_761
1924        };
1925
1926        switch(basechipid) {
1927#ifdef CONFIG_FB_SIS_300
1928        case SIS_540:   nbridgeidx = 0; nbridgenum = 1; break;
1929        case SIS_630:   nbridgeidx = 1; nbridgenum = 2; break;
1930#endif
1931#ifdef CONFIG_FB_SIS_315
1932        case SIS_550:   nbridgeidx = 3; nbridgenum = 1; break;
1933        case SIS_650:   nbridgeidx = 4; nbridgenum = 3; break;
1934        case SIS_660:   nbridgeidx = 7; nbridgenum = 5; break;
1935#endif
1936        default:        return NULL;
1937        }
1938        for(i = 0; i < nbridgenum; i++) {
1939                if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
1940                                nbridgeids[nbridgeidx+i], NULL)))
1941                        break;
1942        }
1943        return pdev;
1944}
1945
1946static int __devinit
1947sisfb_get_dram_size(struct sis_video_info *ivideo)
1948{
1949#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1950        u8 reg;
1951#endif
1952
1953        ivideo->video_size = 0;
1954        ivideo->UMAsize = ivideo->LFBsize = 0;
1955
1956        switch(ivideo->chip) {
1957#ifdef CONFIG_FB_SIS_300
1958        case SIS_300:
1959                inSISIDXREG(SISSR, 0x14, reg);
1960                ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1961                break;
1962        case SIS_540:
1963        case SIS_630:
1964        case SIS_730:
1965                if(!ivideo->nbridge)
1966                        return -1;
1967                pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
1968                ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1969                break;
1970#endif
1971#ifdef CONFIG_FB_SIS_315
1972        case SIS_315H:
1973        case SIS_315PRO:
1974        case SIS_315:
1975                inSISIDXREG(SISSR, 0x14, reg);
1976                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1977                switch((reg >> 2) & 0x03) {
1978                case 0x01:
1979                case 0x03:
1980                        ivideo->video_size <<= 1;
1981                        break;
1982                case 0x02:
1983                        ivideo->video_size += (ivideo->video_size/2);
1984                }
1985                break;
1986        case SIS_330:
1987                inSISIDXREG(SISSR, 0x14, reg);
1988                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1989                if(reg & 0x0c) ivideo->video_size <<= 1;
1990                break;
1991        case SIS_550:
1992        case SIS_650:
1993        case SIS_740:
1994                inSISIDXREG(SISSR, 0x14, reg);
1995                ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
1996                break;
1997        case SIS_661:
1998        case SIS_741:
1999                inSISIDXREG(SISCR, 0x79, reg);
2000                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2001                break;
2002        case SIS_660:
2003        case SIS_760:
2004        case SIS_761:
2005                inSISIDXREG(SISCR, 0x79, reg);
2006                reg = (reg & 0xf0) >> 4;
2007                if(reg) {
2008                        ivideo->video_size = (1 << reg) << 20;
2009                        ivideo->UMAsize = ivideo->video_size;
2010                }
2011                inSISIDXREG(SISCR, 0x78, reg);
2012                reg &= 0x30;
2013                if(reg) {
2014                        if(reg == 0x10) {
2015                                ivideo->LFBsize = (32 << 20);
2016                        } else {
2017                                ivideo->LFBsize = (64 << 20);
2018                        }
2019                        ivideo->video_size += ivideo->LFBsize;
2020                }
2021                break;
2022        case SIS_340:
2023        case XGI_20:
2024        case XGI_40:
2025                inSISIDXREG(SISSR, 0x14, reg);
2026                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2027                if(ivideo->chip != XGI_20) {
2028                        reg = (reg & 0x0c) >> 2;
2029                        if(ivideo->revision_id == 2) {
2030                                if(reg & 0x01) reg = 0x02;
2031                                else           reg = 0x00;
2032                        }
2033                        if(reg == 0x02)         ivideo->video_size <<= 1;
2034                        else if(reg == 0x03)    ivideo->video_size <<= 2;
2035                }
2036                break;
2037#endif
2038        default:
2039                return -1;
2040        }
2041        return 0;
2042}
2043
2044/* -------------- video bridge device detection --------------- */
2045
2046static void __devinit
2047sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2048{
2049        u8 cr32, temp;
2050
2051        /* No CRT2 on XGI Z7 */
2052        if(ivideo->chip == XGI_20) {
2053                ivideo->sisfb_crt1off = 0;
2054                return;
2055        }
2056
2057#ifdef CONFIG_FB_SIS_300
2058        if(ivideo->sisvga_engine == SIS_300_VGA) {
2059                inSISIDXREG(SISSR, 0x17, temp);
2060                if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2061                        /* PAL/NTSC is stored on SR16 on such machines */
2062                        if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2063                                inSISIDXREG(SISSR, 0x16, temp);
2064                                if(temp & 0x20)
2065                                        ivideo->vbflags |= TV_PAL;
2066                                else
2067                                        ivideo->vbflags |= TV_NTSC;
2068                        }
2069                }
2070        }
2071#endif
2072
2073        inSISIDXREG(SISCR, 0x32, cr32);
2074
2075        if(cr32 & SIS_CRT1) {
2076                ivideo->sisfb_crt1off = 0;
2077        } else {
2078                ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2079        }
2080
2081        ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2082
2083        if(cr32 & SIS_VB_TV)   ivideo->vbflags |= CRT2_TV;
2084        if(cr32 & SIS_VB_LCD)  ivideo->vbflags |= CRT2_LCD;
2085        if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2086
2087        /* Check given parms for hardware compatibility.
2088         * (Cannot do this in the search_xx routines since we don't
2089         * know what hardware we are running on then)
2090         */
2091
2092        if(ivideo->chip != SIS_550) {
2093           ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2094        }
2095
2096        if(ivideo->sisfb_tvplug != -1) {
2097           if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2098               (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2099              if(ivideo->sisfb_tvplug & TV_YPBPR) {
2100                 ivideo->sisfb_tvplug = -1;
2101                 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2102              }
2103           }
2104        }
2105        if(ivideo->sisfb_tvplug != -1) {
2106           if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2107               (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2108              if(ivideo->sisfb_tvplug & TV_HIVISION) {
2109                 ivideo->sisfb_tvplug = -1;
2110                 printk(KERN_ERR "sisfb: HiVision not supported\n");
2111              }
2112           }
2113        }
2114        if(ivideo->sisfb_tvstd != -1) {
2115           if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2116               (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2117                        (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2118              if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2119                 ivideo->sisfb_tvstd = -1;
2120                 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2121              }
2122           }
2123        }
2124
2125        /* Detect/set TV plug & type */
2126        if(ivideo->sisfb_tvplug != -1) {
2127                ivideo->vbflags |= ivideo->sisfb_tvplug;
2128        } else {
2129                if(cr32 & SIS_VB_YPBPR)          ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2130                else if(cr32 & SIS_VB_HIVISION)  ivideo->vbflags |= TV_HIVISION;
2131                else if(cr32 & SIS_VB_SCART)     ivideo->vbflags |= TV_SCART;
2132                else {
2133                        if(cr32 & SIS_VB_SVIDEO)    ivideo->vbflags |= TV_SVIDEO;
2134                        if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2135                }
2136        }
2137
2138        if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2139            if(ivideo->sisfb_tvstd != -1) {
2140               ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2141               ivideo->vbflags |= ivideo->sisfb_tvstd;
2142            }
2143            if(ivideo->vbflags & TV_SCART) {
2144               ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2145               ivideo->vbflags |= TV_PAL;
2146            }
2147            if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2148                if(ivideo->sisvga_engine == SIS_300_VGA) {
2149                        inSISIDXREG(SISSR, 0x38, temp);
2150                        if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2151                        else            ivideo->vbflags |= TV_NTSC;
2152                } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2153                        inSISIDXREG(SISSR, 0x38, temp);
2154                        if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2155                        else            ivideo->vbflags |= TV_NTSC;
2156                } else {
2157                        inSISIDXREG(SISCR, 0x79, temp);
2158                        if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2159                        else            ivideo->vbflags |= TV_NTSC;
2160                }
2161            }
2162        }
2163
2164        /* Copy forceCRT1 option to CRT1off if option is given */
2165        if(ivideo->sisfb_forcecrt1 != -1) {
2166           ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2167        }
2168}
2169
2170/* ------------------ Sensing routines ------------------ */
2171
2172static bool __devinit
2173sisfb_test_DDC1(struct sis_video_info *ivideo)
2174{
2175    unsigned short old;
2176    int count = 48;
2177
2178    old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2179    do {
2180        if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2181    } while(count--);
2182    return (count != -1);
2183}
2184
2185static void __devinit
2186sisfb_sense_crt1(struct sis_video_info *ivideo)
2187{
2188    bool mustwait = false;
2189    u8  sr1F, cr17;
2190#ifdef CONFIG_FB_SIS_315
2191    u8  cr63=0;
2192#endif
2193    u16 temp = 0xffff;
2194    int i;
2195
2196    inSISIDXREG(SISSR,0x1F,sr1F);
2197    orSISIDXREG(SISSR,0x1F,0x04);
2198    andSISIDXREG(SISSR,0x1F,0x3F);
2199    if(sr1F & 0xc0) mustwait = true;
2200
2201#ifdef CONFIG_FB_SIS_315
2202    if(ivideo->sisvga_engine == SIS_315_VGA) {
2203       inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2204       cr63 &= 0x40;
2205       andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2206    }
2207#endif
2208
2209    inSISIDXREG(SISCR,0x17,cr17);
2210    cr17 &= 0x80;
2211    if(!cr17) {
2212       orSISIDXREG(SISCR,0x17,0x80);
2213       mustwait = true;
2214       outSISIDXREG(SISSR, 0x00, 0x01);
2215       outSISIDXREG(SISSR, 0x00, 0x03);
2216    }
2217
2218    if(mustwait) {
2219       for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2220    }
2221
2222#ifdef CONFIG_FB_SIS_315
2223    if(ivideo->chip >= SIS_330) {
2224       andSISIDXREG(SISCR,0x32,~0x20);
2225       if(ivideo->chip >= SIS_340) {
2226          outSISIDXREG(SISCR, 0x57, 0x4a);
2227       } else {
2228          outSISIDXREG(SISCR, 0x57, 0x5f);
2229       }
2230       orSISIDXREG(SISCR, 0x53, 0x02);
2231       while((inSISREG(SISINPSTAT)) & 0x01)    break;
2232       while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2233       if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2234       andSISIDXREG(SISCR, 0x53, 0xfd);
2235       andSISIDXREG(SISCR, 0x57, 0x00);
2236    }
2237#endif
2238
2239    if(temp == 0xffff) {
2240       i = 3;
2241       do {
2242          temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2243                ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2244       } while(((temp == 0) || (temp == 0xffff)) && i--);
2245
2246       if((temp == 0) || (temp == 0xffff)) {
2247          if(sisfb_test_DDC1(ivideo)) temp = 1;
2248       }
2249    }
2250
2251    if((temp) && (temp != 0xffff)) {
2252       orSISIDXREG(SISCR,0x32,0x20);
2253    }
2254
2255#ifdef CONFIG_FB_SIS_315
2256    if(ivideo->sisvga_engine == SIS_315_VGA) {
2257       setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2258    }
2259#endif
2260
2261    setSISIDXREG(SISCR,0x17,0x7F,cr17);
2262
2263    outSISIDXREG(SISSR,0x1F,sr1F);
2264}
2265
2266/* Determine and detect attached devices on SiS30x */
2267static void __devinit
2268SiS_SenseLCD(struct sis_video_info *ivideo)
2269{
2270        unsigned char buffer[256];
2271        unsigned short temp, realcrtno, i;
2272        u8 reg, cr37 = 0, paneltype = 0;
2273        u16 xres, yres;
2274
2275        ivideo->SiS_Pr.PanelSelfDetected = false;
2276
2277        /* LCD detection only for TMDS bridges */
2278        if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2279                return;
2280        if(ivideo->vbflags2 & VB2_30xBDH)
2281                return;
2282
2283        /* If LCD already set up by BIOS, skip it */
2284        inSISIDXREG(SISCR, 0x32, reg);
2285        if(reg & 0x08)
2286                return;
2287
2288        realcrtno = 1;
2289        if(ivideo->SiS_Pr.DDCPortMixup)
2290                realcrtno = 0;
2291
2292        /* Check DDC capabilities */
2293        temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2294                                realcrtno, 0, &buffer[0], ivideo->vbflags2);
2295
2296        if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2297                return;
2298
2299        /* Read DDC data */
2300        i = 3;  /* Number of retrys */
2301        do {
2302                temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2303                                ivideo->sisvga_engine, realcrtno, 1,
2304                                &buffer[0], ivideo->vbflags2);
2305        } while((temp) && i--);
2306
2307        if(temp)
2308                return;
2309
2310        /* No digital device */
2311        if(!(buffer[0x14] & 0x80))
2312                return;
2313
2314        /* First detailed timing preferred timing? */
2315        if(!(buffer[0x18] & 0x02))
2316                return;
2317
2318        xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2319        yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2320
2321        switch(xres) {
2322                case 1024:
2323                        if(yres == 768)
2324                                paneltype = 0x02;
2325                        break;
2326                case 1280:
2327                        if(yres == 1024)
2328                                paneltype = 0x03;
2329                        break;
2330                case 1600:
2331                        if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2332                                paneltype = 0x0b;
2333                        break;
2334        }
2335
2336        if(!paneltype)
2337                return;
2338
2339        if(buffer[0x23])
2340                cr37 |= 0x10;
2341
2342        if((buffer[0x47] & 0x18) == 0x18)
2343                cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2344        else
2345                cr37 |= 0xc0;
2346
2347        outSISIDXREG(SISCR, 0x36, paneltype);
2348        cr37 &= 0xf1;
2349        setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2350        orSISIDXREG(SISCR, 0x32, 0x08);
2351
2352        ivideo->SiS_Pr.PanelSelfDetected = true;
2353}
2354
2355static int __devinit
2356SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2357{
2358    int temp, mytest, result, i, j;
2359
2360    for(j = 0; j < 10; j++) {
2361       result = 0;
2362       for(i = 0; i < 3; i++) {
2363          mytest = test;
2364          outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2365          temp = (type >> 8) | (mytest & 0x00ff);
2366          setSISIDXREG(SISPART4,0x10,0xe0,temp);
2367          SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2368          mytest >>= 8;
2369          mytest &= 0x7f;
2370          inSISIDXREG(SISPART4,0x03,temp);
2371          temp ^= 0x0e;
2372          temp &= mytest;
2373          if(temp == mytest) result++;
2374#if 1
2375          outSISIDXREG(SISPART4,0x11,0x00);
2376          andSISIDXREG(SISPART4,0x10,0xe0);
2377          SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2378#endif
2379       }
2380       if((result == 0) || (result >= 2)) break;
2381    }
2382    return result;
2383}
2384
2385static void __devinit
2386SiS_Sense30x(struct sis_video_info *ivideo)
2387{
2388    u8  backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2389    u16 svhs=0, svhs_c=0;
2390    u16 cvbs=0, cvbs_c=0;
2391    u16 vga2=0, vga2_c=0;
2392    int myflag, result;
2393    char stdstr[] = "sisfb: Detected";
2394    char tvstr[]  = "TV connected to";
2395
2396    if(ivideo->vbflags2 & VB2_301) {
2397       svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2398       inSISIDXREG(SISPART4,0x01,myflag);
2399       if(myflag & 0x04) {
2400          svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2401       }
2402    } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2403       svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2404    } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2405       svhs = 0x0200; cvbs = 0x0100;
2406    } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2407       svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2408    } else
2409       return;
2410
2411    vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2412    if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2413       svhs_c = 0x0408; cvbs_c = 0x0808;
2414    }
2415
2416    biosflag = 2;
2417    if(ivideo->haveXGIROM) {
2418       biosflag = ivideo->bios_abase[0x58] & 0x03;
2419    } else if(ivideo->newrom) {
2420       if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2421    } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2422       if(ivideo->bios_abase) {
2423          biosflag = ivideo->bios_abase[0xfe] & 0x03;
2424       }
2425    }
2426
2427    if(ivideo->chip == SIS_300) {
2428       inSISIDXREG(SISSR,0x3b,myflag);
2429       if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2430    }
2431
2432    if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2433       vga2 = vga2_c = 0;
2434    }
2435
2436    inSISIDXREG(SISSR,0x1e,backupSR_1e);
2437    orSISIDXREG(SISSR,0x1e,0x20);
2438
2439    inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2440    if(ivideo->vbflags2 & VB2_30xC) {
2441       setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2442    } else {
2443       orSISIDXREG(SISPART4,0x0d,0x04);
2444    }
2445    SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2446
2447    inSISIDXREG(SISPART2,0x00,backupP2_00);
2448    outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2449
2450    inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2451    if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2452       outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2453    }
2454
2455    if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2456       SISDoSense(ivideo, 0, 0);
2457    }
2458
2459    andSISIDXREG(SISCR, 0x32, ~0x14);
2460
2461    if(vga2_c || vga2) {
2462       if(SISDoSense(ivideo, vga2, vga2_c)) {
2463          if(biosflag & 0x01) {
2464             printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2465             orSISIDXREG(SISCR, 0x32, 0x04);
2466          } else {
2467             printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2468             orSISIDXREG(SISCR, 0x32, 0x10);
2469          }
2470       }
2471    }
2472
2473    andSISIDXREG(SISCR, 0x32, 0x3f);
2474
2475    if(ivideo->vbflags2 & VB2_30xCLV) {
2476       orSISIDXREG(SISPART4,0x0d,0x04);
2477    }
2478
2479    if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2480       outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2481       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2482       if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2483          if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2484             printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2485             orSISIDXREG(SISCR,0x32,0x80);
2486          }
2487       }
2488       outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2489    }
2490
2491    andSISIDXREG(SISCR, 0x32, ~0x03);
2492
2493    if(!(ivideo->vbflags & TV_YPBPR)) {
2494       if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2495          printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2496          orSISIDXREG(SISCR, 0x32, 0x02);
2497       }
2498       if((biosflag & 0x02) || (!result)) {
2499          if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2500             printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2501             orSISIDXREG(SISCR, 0x32, 0x01);
2502          }
2503       }
2504    }
2505
2506    SISDoSense(ivideo, 0, 0);
2507
2508    outSISIDXREG(SISPART2,0x00,backupP2_00);
2509    outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2510    outSISIDXREG(SISSR,0x1e,backupSR_1e);
2511
2512    if(ivideo->vbflags2 & VB2_30xCLV) {
2513       inSISIDXREG(SISPART2,0x00,biosflag);
2514       if(biosflag & 0x20) {
2515          for(myflag = 2; myflag > 0; myflag--) {
2516             biosflag ^= 0x20;
2517             outSISIDXREG(SISPART2,0x00,biosflag);
2518          }
2519       }
2520    }
2521
2522    outSISIDXREG(SISPART2,0x00,backupP2_00);
2523}
2524
2525/* Determine and detect attached TV's on Chrontel */
2526static void __devinit
2527SiS_SenseCh(struct sis_video_info *ivideo)
2528{
2529#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2530    u8 temp1, temp2;
2531    char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2532#endif
2533#ifdef CONFIG_FB_SIS_300
2534    unsigned char test[3];
2535    int i;
2536#endif
2537
2538    if(ivideo->chip < SIS_315H) {
2539
2540#ifdef CONFIG_FB_SIS_300
2541       ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1;            /* Chrontel 700x */
2542       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c);      /* Set general purpose IO for Chrontel communication */
2543       SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2544       temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2545       /* See Chrontel TB31 for explanation */
2546       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2547       if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2548          SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2549          SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2550       }
2551       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2552       if(temp2 != temp1) temp1 = temp2;
2553
2554       if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2555           /* Read power status */
2556           temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2557           if((temp1 & 0x03) != 0x03) {
2558                /* Power all outputs */
2559                SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2560                SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2561           }
2562           /* Sense connected TV devices */
2563           for(i = 0; i < 3; i++) {
2564               SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2565               SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2566               SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2567               SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2568               temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2569               if(!(temp1 & 0x08))       test[i] = 0x02;
2570               else if(!(temp1 & 0x02))  test[i] = 0x01;
2571               else                      test[i] = 0;
2572               SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2573           }
2574
2575           if(test[0] == test[1])      temp1 = test[0];
2576           else if(test[0] == test[2]) temp1 = test[0];
2577           else if(test[1] == test[2]) temp1 = test[1];
2578           else {
2579                printk(KERN_INFO
2580                        "sisfb: TV detection unreliable - test results varied\n");
2581                temp1 = test[2];
2582           }
2583           if(temp1 == 0x02) {
2584                printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2585                ivideo->vbflags |= TV_SVIDEO;
2586                orSISIDXREG(SISCR, 0x32, 0x02);
2587                andSISIDXREG(SISCR, 0x32, ~0x05);
2588           } else if (temp1 == 0x01) {
2589                printk(KERN_INFO "%s CVBS output\n", stdstr);
2590                ivideo->vbflags |= TV_AVIDEO;
2591                orSISIDXREG(SISCR, 0x32, 0x01);
2592                andSISIDXREG(SISCR, 0x32, ~0x06);
2593           } else {
2594                SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2595                andSISIDXREG(SISCR, 0x32, ~0x07);
2596           }
2597       } else if(temp1 == 0) {
2598          SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2599          andSISIDXREG(SISCR, 0x32, ~0x07);
2600       }
2601       /* Set general purpose IO for Chrontel communication */
2602       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2603#endif
2604
2605    } else {
2606
2607#ifdef CONFIG_FB_SIS_315
2608        ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2;           /* Chrontel 7019 */
2609        temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2610        SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2611        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2612        temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2613        temp2 |= 0x01;
2614        SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2615        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2616        temp2 ^= 0x01;
2617        SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2618        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2619        temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2620        SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2621        temp1 = 0;
2622        if(temp2 & 0x02) temp1 |= 0x01;
2623        if(temp2 & 0x10) temp1 |= 0x01;
2624        if(temp2 & 0x04) temp1 |= 0x02;
2625        if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2626        switch(temp1) {
2627        case 0x01:
2628             printk(KERN_INFO "%s CVBS output\n", stdstr);
2629             ivideo->vbflags |= TV_AVIDEO;
2630             orSISIDXREG(SISCR, 0x32, 0x01);
2631             andSISIDXREG(SISCR, 0x32, ~0x06);
2632             break;
2633        case 0x02:
2634             printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2635             ivideo->vbflags |= TV_SVIDEO;
2636             orSISIDXREG(SISCR, 0x32, 0x02);
2637             andSISIDXREG(SISCR, 0x32, ~0x05);
2638             break;
2639        case 0x04:
2640             printk(KERN_INFO "%s SCART output\n", stdstr);
2641             orSISIDXREG(SISCR, 0x32, 0x04);
2642             andSISIDXREG(SISCR, 0x32, ~0x03);
2643             break;
2644        default:
2645             andSISIDXREG(SISCR, 0x32, ~0x07);
2646        }
2647#endif
2648    }
2649}
2650
2651static void __devinit
2652sisfb_get_VB_type(struct sis_video_info *ivideo)
2653{
2654        char stdstr[]    = "sisfb: Detected";
2655        char bridgestr[] = "video bridge";
2656        u8 vb_chipid;
2657        u8 reg;
2658
2659        /* No CRT2 on XGI Z7 */
2660        if(ivideo->chip == XGI_20)
2661                return;
2662
2663        inSISIDXREG(SISPART4, 0x00, vb_chipid);
2664        switch(vb_chipid) {
2665        case 0x01:
2666                inSISIDXREG(SISPART4, 0x01, reg);
2667                if(reg < 0xb0) {
2668                        ivideo->vbflags |= VB_301;      /* Deprecated */
2669                        ivideo->vbflags2 |= VB2_301;
2670                        printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2671                } else if(reg < 0xc0) {
2672                        ivideo->vbflags |= VB_301B;     /* Deprecated */
2673                        ivideo->vbflags2 |= VB2_301B;
2674                        inSISIDXREG(SISPART4,0x23,reg);
2675                        if(!(reg & 0x02)) {
2676                           ivideo->vbflags |= VB_30xBDH;        /* Deprecated */
2677                           ivideo->vbflags2 |= VB2_30xBDH;
2678                           printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2679                        } else {
2680                           printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2681                        }
2682                } else if(reg < 0xd0) {
2683                        ivideo->vbflags |= VB_301C;     /* Deprecated */
2684                        ivideo->vbflags2 |= VB2_301C;
2685                        printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2686                } else if(reg < 0xe0) {
2687                        ivideo->vbflags |= VB_301LV;    /* Deprecated */
2688                        ivideo->vbflags2 |= VB2_301LV;
2689                        printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2690                } else if(reg <= 0xe1) {
2691                        inSISIDXREG(SISPART4,0x39,reg);
2692                        if(reg == 0xff) {
2693                           ivideo->vbflags |= VB_302LV; /* Deprecated */
2694                           ivideo->vbflags2 |= VB2_302LV;
2695                           printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2696                        } else {
2697                           ivideo->vbflags |= VB_301C;  /* Deprecated */
2698                           ivideo->vbflags2 |= VB2_301C;
2699                           printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2700#if 0
2701                           ivideo->vbflags |= VB_302ELV;        /* Deprecated */
2702                           ivideo->vbflags2 |= VB2_302ELV;
2703                           printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2704#endif
2705                        }
2706                }
2707                break;
2708        case 0x02:
2709                ivideo->vbflags |= VB_302B;     /* Deprecated */
2710                ivideo->vbflags2 |= VB2_302B;
2711                printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2712                break;
2713        }
2714
2715        if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2716                inSISIDXREG(SISCR, 0x37, reg);
2717                reg &= SIS_EXTERNAL_CHIP_MASK;
2718                reg >>= 1;
2719                if(ivideo->sisvga_engine == SIS_300_VGA) {
2720#ifdef CONFIG_FB_SIS_300
2721                        switch(reg) {
2722                           case SIS_EXTERNAL_CHIP_LVDS:
2723                                ivideo->vbflags |= VB_LVDS;     /* Deprecated */
2724                                ivideo->vbflags2 |= VB2_LVDS;
2725                                break;
2726                           case SIS_EXTERNAL_CHIP_TRUMPION:
2727                                ivideo->vbflags |= (VB_LVDS | VB_TRUMPION);     /* Deprecated */
2728                                ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2729                                break;
2730                           case SIS_EXTERNAL_CHIP_CHRONTEL:
2731                                ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2732                                ivideo->vbflags2 |= VB2_CHRONTEL;
2733                                break;
2734                           case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2735                                ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
2736                                ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2737                                break;
2738                        }
2739                        if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2740#endif
2741                } else if(ivideo->chip < SIS_661) {
2742#ifdef CONFIG_FB_SIS_315
2743                        switch (reg) {
2744                           case SIS310_EXTERNAL_CHIP_LVDS:
2745                                ivideo->vbflags |= VB_LVDS;     /* Deprecated */
2746                                ivideo->vbflags2 |= VB2_LVDS;
2747                                break;
2748                           case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2749                                ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
2750                                ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2751                                break;
2752                        }
2753                        if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2754#endif
2755                } else if(ivideo->chip >= SIS_661) {
2756#ifdef CONFIG_FB_SIS_315
2757                        inSISIDXREG(SISCR, 0x38, reg);
2758                        reg >>= 5;
2759                        switch(reg) {
2760                           case 0x02:
2761                                ivideo->vbflags |= VB_LVDS;     /* Deprecated */
2762                                ivideo->vbflags2 |= VB2_LVDS;
2763                                break;
2764                           case 0x03:
2765                                ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
2766                                ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2767                                break;
2768                           case 0x04:
2769                                ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);     /* Deprecated */
2770                                ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2771                                break;
2772                        }
2773                        if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2774#endif
2775                }
2776                if(ivideo->vbflags2 & VB2_LVDS) {
2777                   printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2778                }
2779                if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2780                   printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2781                }
2782                if(ivideo->vbflags2 & VB2_CHRONTEL) {
2783                   printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2784                }
2785                if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2786                   printk(KERN_INFO "%s Conexant external device\n", stdstr);
2787                }
2788        }
2789
2790        if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2791                SiS_SenseLCD(ivideo);
2792                SiS_Sense30x(ivideo);
2793        } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2794                SiS_SenseCh(ivideo);
2795        }
2796}
2797
2798/* ---------- Engine initialization routines ------------ */
2799
2800static void
2801sisfb_engine_init(struct sis_video_info *ivideo)
2802{
2803
2804        /* Initialize command queue (we use MMIO only) */
2805
2806        /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2807
2808        ivideo->caps &= ~(TURBO_QUEUE_CAP    |
2809                          MMIO_CMD_QUEUE_CAP |
2810                          VM_CMD_QUEUE_CAP   |
2811                          AGP_CMD_QUEUE_CAP);
2812
2813#ifdef CONFIG_FB_SIS_300
2814        if(ivideo->sisvga_engine == SIS_300_VGA) {
2815                u32 tqueue_pos;
2816                u8 tq_state;
2817
2818                tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2819
2820                inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2821                tq_state |= 0xf0;
2822                tq_state &= 0xfc;
2823                tq_state |= (u8)(tqueue_pos >> 8);
2824                outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2825
2826                outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2827
2828                ivideo->caps |= TURBO_QUEUE_CAP;
2829        }
2830#endif
2831
2832#ifdef CONFIG_FB_SIS_315
2833        if(ivideo->sisvga_engine == SIS_315_VGA) {
2834                u32 tempq = 0, templ;
2835                u8  temp;
2836
2837                if(ivideo->chip == XGI_20) {
2838                        switch(ivideo->cmdQueueSize) {
2839                        case (64 * 1024):
2840                                temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2841                                break;
2842                        case (128 * 1024):
2843                        default:
2844                                temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2845                        }
2846                } else {
2847                        switch(ivideo->cmdQueueSize) {
2848                        case (4 * 1024 * 1024):
2849                                temp = SIS_CMD_QUEUE_SIZE_4M;
2850                                break;
2851                        case (2 * 1024 * 1024):
2852                                temp = SIS_CMD_QUEUE_SIZE_2M;
2853                                break;
2854                        case (1 * 1024 * 1024):
2855                                temp = SIS_CMD_QUEUE_SIZE_1M;
2856                                break;
2857                        default:
2858                        case (512 * 1024):
2859                                temp = SIS_CMD_QUEUE_SIZE_512k;
2860                        }
2861                }
2862
2863                outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2864                outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2865
2866                if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2867                        /* Must disable dual pipe on XGI_40. Can't do
2868                         * this in MMIO mode, because it requires
2869                         * setting/clearing a bit in the MMIO fire trigger
2870                         * register.
2871                         */
2872                        if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2873
2874                                MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2875
2876                                outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2877
2878                                tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2879                                MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2880
2881                                tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2882                                MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2883
2884                                writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2885                                writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2886                                writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2887                                writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2888
2889                                MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2890
2891                                sisfb_syncaccel(ivideo);
2892
2893                                outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2894
2895                        }
2896                }
2897
2898                tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2899                MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2900
2901                temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2902                outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2903
2904                tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2905                MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2906
2907                ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2908        }
2909#endif
2910
2911        ivideo->engineok = 1;
2912}
2913
2914static void __devinit
2915sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2916{
2917        u8 reg;
2918        int i;
2919
2920        inSISIDXREG(SISCR, 0x36, reg);
2921        reg &= 0x0f;
2922        if(ivideo->sisvga_engine == SIS_300_VGA) {
2923                ivideo->CRT2LCDType = sis300paneltype[reg];
2924        } else if(ivideo->chip >= SIS_661) {
2925                ivideo->CRT2LCDType = sis661paneltype[reg];
2926        } else {
2927                ivideo->CRT2LCDType = sis310paneltype[reg];
2928                if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2929                        if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2930                           (ivideo->CRT2LCDType != LCD_320x240_3)) {
2931                                ivideo->CRT2LCDType = LCD_320x240;
2932                        }
2933                }
2934        }
2935
2936        if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2937                /* For broken BIOSes: Assume 1024x768, RGB18 */
2938                ivideo->CRT2LCDType = LCD_1024x768;
2939                setSISIDXREG(SISCR,0x36,0xf0,0x02);
2940                setSISIDXREG(SISCR,0x37,0xee,0x01);
2941                printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2942        }
2943
2944        for(i = 0; i < SIS_LCD_NUMBER; i++) {
2945                if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2946                        ivideo->lcdxres = sis_lcd_data[i].xres;
2947                        ivideo->lcdyres = sis_lcd_data[i].yres;
2948                        ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2949                        break;
2950                }
2951        }
2952
2953#ifdef CONFIG_FB_SIS_300
2954        if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2955                ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2956                ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2957        } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2958                ivideo->lcdxres =  848; ivideo->lcdyres =  480;
2959                ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2960        } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2961                ivideo->lcdxres =  856; ivideo->lcdyres =  480;
2962                ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2963        }
2964#endif
2965
2966        printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2967                        ivideo->lcdxres, ivideo->lcdyres);
2968}
2969
2970static void __devinit
2971sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2972{
2973#ifdef CONFIG_FB_SIS_300
2974        /* Save the current PanelDelayCompensation if the LCD is currently used */
2975        if(ivideo->sisvga_engine == SIS_300_VGA) {
2976                if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2977                        int tmp;
2978                        inSISIDXREG(SISCR,0x30,tmp);
2979                        if(tmp & 0x20) {
2980                                /* Currently on LCD? If yes, read current pdc */
2981                                inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
2982                                ivideo->detectedpdc &= 0x3c;
2983                                if(ivideo->SiS_Pr.PDC == -1) {
2984                                        /* Let option override detection */
2985                                        ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2986                                }
2987                                printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2988                                        ivideo->detectedpdc);
2989                        }
2990                        if((ivideo->SiS_Pr.PDC != -1) &&
2991                           (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2992                                printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2993                                        ivideo->SiS_Pr.PDC);
2994                        }
2995                }
2996        }
2997#endif
2998
2999#ifdef CONFIG_FB_SIS_315
3000        if(ivideo->sisvga_engine == SIS_315_VGA) {
3001
3002                /* Try to find about LCDA */
3003                if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3004                        int tmp;
3005                        inSISIDXREG(SISPART1,0x13,tmp);
3006                        if(tmp & 0x04) {
3007                                ivideo->SiS_Pr.SiS_UseLCDA = true;
3008                                ivideo->detectedlcda = 0x03;
3009                        }
3010                }
3011
3012                /* Save PDC */
3013                if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3014                        int tmp;
3015                        inSISIDXREG(SISCR,0x30,tmp);
3016                        if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3017                                /* Currently on LCD? If yes, read current pdc */
3018                                u8 pdc;
3019                                inSISIDXREG(SISPART1,0x2D,pdc);
3020                                ivideo->detectedpdc  = (pdc & 0x0f) << 1;
3021                                ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3022                                inSISIDXREG(SISPART1,0x35,pdc);
3023                                ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3024                                inSISIDXREG(SISPART1,0x20,pdc);
3025                                ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3026                                if(ivideo->newrom) {
3027                                        /* New ROM invalidates other PDC resp. */
3028                                        if(ivideo->detectedlcda != 0xff) {
3029                                                ivideo->detectedpdc = 0xff;
3030                                        } else {
3031                                                ivideo->detectedpdca = 0xff;
3032                                        }
3033                                }
3034                                if(ivideo->SiS_Pr.PDC == -1) {
3035                                        if(ivideo->detectedpdc != 0xff) {
3036                                                ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3037                                        }
3038                                }
3039                                if(ivideo->SiS_Pr.PDCA == -1) {
3040                                        if(ivideo->detectedpdca != 0xff) {
3041                                                ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3042                                        }
3043                                }
3044                                if(ivideo->detectedpdc != 0xff) {
3045                                        printk(KERN_INFO
3046                                                "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3047                                                ivideo->detectedpdc);
3048                                }
3049                                if(ivideo->detectedpdca != 0xff) {
3050                                        printk(KERN_INFO
3051                                                "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3052                                                ivideo->detectedpdca);
3053                                }
3054                        }
3055
3056                        /* Save EMI */
3057                        if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3058                                inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3059                                inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3060                                inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3061                                inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3062                                ivideo->SiS_Pr.HaveEMI = true;
3063                                if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3064                                        ivideo->SiS_Pr.HaveEMILCD = true;
3065                                }
3066                        }
3067                }
3068
3069                /* Let user override detected PDCs (all bridges) */
3070                if(ivideo->vbflags2 & VB2_30xBLV) {
3071                        if((ivideo->SiS_Pr.PDC != -1) &&
3072                           (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3073                                printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3074                                        ivideo->SiS_Pr.PDC);
3075                        }
3076                        if((ivideo->SiS_Pr.PDCA != -1) &&
3077                           (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3078                                printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3079                                 ivideo->SiS_Pr.PDCA);
3080                        }
3081                }
3082
3083        }
3084#endif
3085}
3086
3087/* -------------------- Memory manager routines ---------------------- */
3088
3089static u32 __devinit
3090sisfb_getheapstart(struct sis_video_info *ivideo)
3091{
3092        u32 ret = ivideo->sisfb_parm_mem * 1024;
3093        u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3094        u32 def;
3095
3096        /* Calculate heap start = end of memory for console
3097         *
3098         * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3099         * C = console, D = heap, H = HWCursor, Q = cmd-queue
3100         *
3101         * On 76x in UMA+LFB mode, the layout is as follows:
3102         * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3103         * where the heap is the entire UMA area, eventually
3104         * into the LFB area if the given mem parameter is
3105         * higher than the size of the UMA memory.
3106         *
3107         * Basically given by "mem" parameter
3108         *
3109         * maximum = videosize - cmd_queue - hwcursor
3110         *           (results in a heap of size 0)
3111         * default = SiS 300: depends on videosize
3112         *           SiS 315/330/340/XGI: 32k below max
3113         */
3114
3115        if(ivideo->sisvga_engine == SIS_300_VGA) {
3116                if(ivideo->video_size > 0x1000000) {
3117                        def = 0xc00000;
3118                } else if(ivideo->video_size > 0x800000) {
3119                        def = 0x800000;
3120                } else {
3121                        def = 0x400000;
3122                }
3123        } else if(ivideo->UMAsize && ivideo->LFBsize) {
3124                ret = def = 0;
3125        } else {
3126                def = maxoffs - 0x8000;
3127        }
3128
3129        /* Use default for secondary card for now (FIXME) */
3130        if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3131                ret = def;
3132
3133        return ret;
3134}
3135
3136static u32 __devinit
3137sisfb_getheapsize(struct sis_video_info *ivideo)
3138{
3139        u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3140        u32 ret = 0;
3141
3142        if(ivideo->UMAsize && ivideo->LFBsize) {
3143                if( (!ivideo->sisfb_parm_mem)                   ||
3144                    ((ivideo->sisfb_parm_mem * 1024) > max)     ||
3145                    ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3146                        ret = ivideo->UMAsize;
3147                        max -= ivideo->UMAsize;
3148                } else {
3149                        ret = max - (ivideo->sisfb_parm_mem * 1024);
3150                        max = ivideo->sisfb_parm_mem * 1024;
3151                }
3152                ivideo->video_offset = ret;
3153                ivideo->sisfb_mem = max;
3154        } else {
3155                ret = max - ivideo->heapstart;
3156                ivideo->sisfb_mem = ivideo->heapstart;
3157        }
3158
3159        return ret;
3160}
3161
3162static int __devinit
3163sisfb_heap_init(struct sis_video_info *ivideo)
3164{
3165        struct SIS_OH *poh;
3166
3167        ivideo->video_offset = 0;
3168        if(ivideo->sisfb_parm_mem) {
3169                if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3170                    (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3171                        ivideo->sisfb_parm_mem = 0;
3172                }
3173        }
3174
3175        ivideo->heapstart = sisfb_getheapstart(ivideo);
3176        ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3177
3178        ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3179        ivideo->sisfb_heap_end   = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3180
3181        printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3182                (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3183
3184        ivideo->sisfb_heap.vinfo = ivideo;
3185
3186        ivideo->sisfb_heap.poha_chain = NULL;
3187        ivideo->sisfb_heap.poh_freelist = NULL;
3188
3189        poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3190        if(poh == NULL)
3191                return 1;
3192
3193        poh->poh_next = &ivideo->sisfb_heap.oh_free;
3194        poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3195        poh->size = ivideo->sisfb_heap_size;
3196        poh->offset = ivideo->heapstart;
3197
3198        ivideo->sisfb_heap.oh_free.poh_next = poh;
3199        ivideo->sisfb_heap.oh_free.poh_prev = poh;
3200        ivideo->sisfb_heap.oh_free.size = 0;
3201        ivideo->sisfb_heap.max_freesize = poh->size;
3202
3203        ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3204        ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3205        ivideo->sisfb_heap.oh_used.size = SENTINEL;
3206
3207        if(ivideo->cardnumber == 0) {
3208                /* For the first card, make this heap the "global" one
3209                 * for old DRM (which could handle only one card)
3210                 */
3211                sisfb_heap = &ivideo->sisfb_heap;
3212        }
3213
3214        return 0;
3215}
3216
3217static struct SIS_OH *
3218sisfb_poh_new_node(struct SIS_HEAP *memheap)
3219{
3220        struct SIS_OHALLOC      *poha;
3221        struct SIS_OH           *poh;
3222        unsigned long           cOhs;
3223        int                     i;
3224
3225        if(memheap->poh_freelist == NULL) {
3226                poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3227                if(!poha)
3228                        return NULL;
3229
3230                poha->poha_next = memheap->poha_chain;
3231                memheap->poha_chain = poha;
3232
3233                cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3234
3235                poh = &poha->aoh[0];
3236                for(i = cOhs - 1; i != 0; i--) {
3237                        poh->poh_next = poh + 1;
3238                        poh = poh + 1;
3239                }
3240
3241                poh->poh_next = NULL;
3242                memheap->poh_freelist = &poha->aoh[0];
3243        }
3244
3245        poh = memheap->poh_freelist;
3246        memheap->poh_freelist = poh->poh_next;
3247
3248        return poh;
3249}
3250
3251static struct SIS_OH *
3252sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3253{
3254        struct SIS_OH   *pohThis;
3255        struct SIS_OH   *pohRoot;
3256        int             bAllocated = 0;
3257
3258        if(size > memheap->max_freesize) {
3259                DPRINTK("sisfb: Can't allocate %dk video memory\n",
3260                        (unsigned int) size / 1024);
3261                return NULL;
3262        }
3263
3264        pohThis = memheap->oh_free.poh_next;
3265
3266        while(pohThis != &memheap->oh_free) {
3267                if(size <= pohThis->size) {
3268                        bAllocated = 1;
3269                        break;
3270                }
3271                pohThis = pohThis->poh_next;
3272        }
3273
3274        if(!bAllocated) {
3275                DPRINTK("sisfb: Can't allocate %dk video memory\n",
3276                        (unsigned int) size / 1024);
3277                return NULL;
3278        }
3279
3280        if(size == pohThis->size) {
3281                pohRoot = pohThis;
3282                sisfb_delete_node(pohThis);
3283        } else {
3284                pohRoot = sisfb_poh_new_node(memheap);
3285                if(pohRoot == NULL)
3286                        return NULL;
3287
3288                pohRoot->offset = pohThis->offset;
3289                pohRoot->size = size;
3290
3291                pohThis->offset += size;
3292                pohThis->size -= size;
3293        }
3294
3295        memheap->max_freesize -= size;
3296
3297        pohThis = &memheap->oh_used;
3298        sisfb_insert_node(pohThis, pohRoot);
3299
3300        return pohRoot;
3301}
3302
3303static void
3304sisfb_delete_node(struct SIS_OH *poh)
3305{
3306        poh->poh_prev->poh_next = poh->poh_next;
3307        poh->poh_next->poh_prev = poh->poh_prev;
3308}
3309
3310static void
3311sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3312{
3313        struct SIS_OH *pohTemp = pohList->poh_next;
3314
3315        pohList->poh_next = poh;
3316        pohTemp->poh_prev = poh;
3317
3318        poh->poh_prev = pohList;
3319        poh->poh_next = pohTemp;
3320}
3321
3322static struct SIS_OH *
3323sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3324{
3325        struct SIS_OH *pohThis;
3326        struct SIS_OH *poh_freed;
3327        struct SIS_OH *poh_prev;
3328        struct SIS_OH *poh_next;
3329        u32    ulUpper;
3330        u32    ulLower;
3331        int    foundNode = 0;
3332
3333        poh_freed = memheap->oh_used.poh_next;
3334
3335        while(poh_freed != &memheap->oh_used) {
3336                if(poh_freed->offset == base) {
3337                        foundNode = 1;
3338                        break;
3339                }
3340
3341                poh_freed = poh_freed->poh_next;
3342        }
3343
3344        if(!foundNode)
3345                return NULL;
3346
3347        memheap->max_freesize += poh_freed->size;
3348
3349        poh_prev = poh_next = NULL;
3350        ulUpper = poh_freed->offset + poh_freed->size;
3351        ulLower = poh_freed->offset;
3352
3353        pohThis = memheap->oh_free.poh_next;
3354
3355        while(pohThis != &memheap->oh_free) {
3356                if(pohThis->offset == ulUpper) {
3357                        poh_next = pohThis;
3358                } else if((pohThis->offset + pohThis->size) == ulLower) {
3359                        poh_prev = pohThis;
3360                }
3361                pohThis = pohThis->poh_next;
3362        }
3363
3364        sisfb_delete_node(poh_freed);
3365
3366        if(poh_prev && poh_next) {
3367                poh_prev->size += (poh_freed->size + poh_next->size);
3368                sisfb_delete_node(poh_next);
3369                sisfb_free_node(memheap, poh_freed);
3370                sisfb_free_node(memheap, poh_next);
3371                return poh_prev;
3372        }
3373
3374        if(poh_prev) {
3375                poh_prev->size += poh_freed->size;
3376                sisfb_free_node(memheap, poh_freed);
3377                return poh_prev;
3378        }
3379
3380        if(poh_next) {
3381                poh_next->size += poh_freed->size;
3382                poh_next->offset = poh_freed->offset;
3383                sisfb_free_node(memheap, poh_freed);
3384                return poh_next;
3385        }
3386
3387        sisfb_insert_node(&memheap->oh_free, poh_freed);
3388
3389        return poh_freed;
3390}
3391
3392static void
3393sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3394{
3395        if(poh == NULL)
3396                return;
3397
3398        poh->poh_next = memheap->poh_freelist;
3399        memheap->poh_freelist = poh;
3400}
3401
3402static void
3403sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3404{
3405        struct SIS_OH *poh = NULL;
3406
3407        if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3408                poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3409
3410        if(poh == NULL) {
3411                req->offset = req->size = 0;
3412                DPRINTK("sisfb: Video RAM allocation failed\n");
3413        } else {
3414                req->offset = poh->offset;
3415                req->size = poh->size;
3416                DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3417                        (poh->offset + ivideo->video_vbase));
3418        }
3419}
3420
3421void
3422sis_malloc(struct sis_memreq *req)
3423{
3424        struct sis_video_info *ivideo = sisfb_heap->vinfo;
3425
3426        if(&ivideo->sisfb_heap == sisfb_heap)
3427                sis_int_malloc(ivideo, req);
3428        else
3429                req->offset = req->size = 0;
3430}
3431
3432void
3433sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3434{
3435        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3436
3437        sis_int_malloc(ivideo, req);
3438}
3439
3440/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3441
3442static void
3443sis_int_free(struct sis_video_info *ivideo, u32 base)
3444{
3445        struct SIS_OH *poh;
3446
3447        if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3448                return;
3449
3450        poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3451
3452        if(poh == NULL) {
3453                DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3454                        (unsigned int) base);
3455        }
3456}
3457
3458void
3459sis_free(u32 base)
3460{
3461        struct sis_video_info *ivideo = sisfb_heap->vinfo;
3462
3463        sis_int_free(ivideo, base);
3464}
3465
3466void
3467sis_free_new(struct pci_dev *pdev, u32 base)
3468{
3469        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3470
3471        sis_int_free(ivideo, base);
3472}
3473
3474/* --------------------- SetMode routines ------------------------- */
3475
3476static void
3477sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3478{
3479        u8 cr30, cr31;
3480
3481        /* Check if MMIO and engines are enabled,
3482         * and sync in case they are. Can't use
3483         * ivideo->accel here, as this might have
3484         * been changed before this is called.
3485         */
3486        inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3487        inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3488        /* MMIO and 2D/3D engine enabled? */
3489        if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3490#ifdef CONFIG_FB_SIS_300
3491                if(ivideo->sisvga_engine == SIS_300_VGA) {
3492                        /* Don't care about TurboQueue. It's
3493                         * enough to know that the engines
3494                         * are enabled
3495                         */
3496                        sisfb_syncaccel(ivideo);
3497                }
3498#endif
3499#ifdef CONFIG_FB_SIS_315
3500                if(ivideo->sisvga_engine == SIS_315_VGA) {
3501                        /* Check that any queue mode is
3502                         * enabled, and that the queue
3503                         * is not in the state of "reset"
3504                         */
3505                        inSISIDXREG(SISSR, 0x26, cr30);
3506                        if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3507                                sisfb_syncaccel(ivideo);
3508                        }
3509                }
3510#endif
3511        }
3512}
3513
3514static void
3515sisfb_pre_setmode(struct sis_video_info *ivideo)
3516{
3517        u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3518        int tvregnum = 0;
3519
3520        ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3521
3522        outSISIDXREG(SISSR, 0x05, 0x86);
3523
3524        inSISIDXREG(SISCR, 0x31, cr31);
3525        cr31 &= ~0x60;
3526        cr31 |= 0x04;
3527
3528        cr33 = ivideo->rate_idx & 0x0F;
3529
3530#ifdef CONFIG_FB_SIS_315
3531        if(ivideo->sisvga_engine == SIS_315_VGA) {
3532           if(ivideo->chip >= SIS_661) {
3533              inSISIDXREG(SISCR, 0x38, cr38);
3534              cr38 &= ~0x07;  /* Clear LCDA/DualEdge and YPbPr bits */
3535           } else {
3536              tvregnum = 0x38;
3537              inSISIDXREG(SISCR, tvregnum, cr38);
3538              cr38 &= ~0x3b;  /* Clear LCDA/DualEdge and YPbPr bits */
3539           }
3540        }
3541#endif
3542#ifdef CONFIG_FB_SIS_300
3543        if(ivideo->sisvga_engine == SIS_300_VGA) {
3544           tvregnum = 0x35;
3545           inSISIDXREG(SISCR, tvregnum, cr38);
3546        }
3547#endif
3548
3549        SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3550        SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
3551        ivideo->curFSTN = ivideo->curDSTN = 0;
3552
3553        switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3554
3555           case CRT2_TV:
3556              cr38 &= ~0xc0;   /* Clear PAL-M / PAL-N bits */
3557              if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3558#ifdef CONFIG_FB_SIS_315
3559                 if(ivideo->chip >= SIS_661) {
3560                    cr38 |= 0x04;
3561                    if(ivideo->vbflags & TV_YPBPR525P)       cr35 |= 0x20;
3562                    else if(ivideo->vbflags & TV_YPBPR750P)  cr35 |= 0x40;
3563                    else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3564                    cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3565                    cr35 &= ~0x01;
3566                    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3567                 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3568                    cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3569                    cr38 |= 0x08;
3570                    if(ivideo->vbflags & TV_YPBPR525P)       cr38 |= 0x10;
3571                    else if(ivideo->vbflags & TV_YPBPR750P)  cr38 |= 0x20;
3572                    else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3573                    cr31 &= ~0x01;
3574                    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3575                 }
3576#endif
3577              } else if((ivideo->vbflags & TV_HIVISION) &&
3578                                (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3579                 if(ivideo->chip >= SIS_661) {
3580                    cr38 |= 0x04;
3581                    cr35 |= 0x60;
3582                 } else {
3583                    cr30 |= 0x80;
3584                 }
3585                 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3586                 cr31 |= 0x01;
3587                 cr35 |= 0x01;
3588                 ivideo->currentvbflags |= TV_HIVISION;
3589              } else if(ivideo->vbflags & TV_SCART) {
3590                 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3591                 cr31 |= 0x01;
3592                 cr35 |= 0x01;
3593                 ivideo->currentvbflags |= TV_SCART;
3594              } else {
3595                 if(ivideo->vbflags & TV_SVIDEO) {
3596                    cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3597                    ivideo->currentvbflags |= TV_SVIDEO;
3598                 }
3599                 if(ivideo->vbflags & TV_AVIDEO) {
3600                    cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3601                    ivideo->currentvbflags |= TV_AVIDEO;
3602                 }
3603              }
3604              cr31 |= SIS_DRIVER_MODE;
3605
3606              if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3607                 if(ivideo->vbflags & TV_PAL) {
3608                    cr31 |= 0x01; cr35 |= 0x01;
3609                    ivideo->currentvbflags |= TV_PAL;
3610                    if(ivideo->vbflags & TV_PALM) {
3611                       cr38 |= 0x40; cr35 |= 0x04;
3612                       ivideo->currentvbflags |= TV_PALM;
3613                    } else if(ivideo->vbflags & TV_PALN) {
3614                       cr38 |= 0x80; cr35 |= 0x08;
3615                       ivideo->currentvbflags |= TV_PALN;
3616                    }
3617                 } else {
3618                    cr31 &= ~0x01; cr35 &= ~0x01;
3619                    ivideo->currentvbflags |= TV_NTSC;
3620                    if(ivideo->vbflags & TV_NTSCJ) {
3621                       cr38 |= 0x40; cr35 |= 0x02;
3622                       ivideo->currentvbflags |= TV_NTSCJ;
3623                    }
3624                 }
3625              }
3626              break;
3627
3628           case CRT2_LCD:
3629              cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3630              cr31 |= SIS_DRIVER_MODE;
3631              SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3632              SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3633              ivideo->curFSTN = ivideo->sisfb_fstn;
3634              ivideo->curDSTN = ivideo->sisfb_dstn;
3635              break;
3636
3637           case CRT2_VGA:
3638              cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3639              cr31 |= SIS_DRIVER_MODE;
3640              if(ivideo->sisfb_nocrt2rate) {
3641                 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3642              } else {
3643                 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3644              }
3645              break;
3646
3647           default:     /* disable CRT2 */
3648              cr30 = 0x00;
3649              cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3650        }
3651
3652        outSISIDXREG(SISCR, 0x30, cr30);
3653        outSISIDXREG(SISCR, 0x33, cr33);
3654
3655        if(ivideo->chip >= SIS_661) {
3656#ifdef CONFIG_FB_SIS_315
3657           cr31 &= ~0x01;                          /* Clear PAL flag (now in CR35) */
3658           setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3659           cr38 &= 0x07;                           /* Use only LCDA and HiVision/YPbPr bits */
3660           setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3661#endif
3662        } else if(ivideo->chip != SIS_300) {
3663           outSISIDXREG(SISCR, tvregnum, cr38);
3664        }
3665        outSISIDXREG(SISCR, 0x31, cr31);
3666
3667        ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3668
3669        sisfb_check_engine_and_sync(ivideo);
3670}
3671
3672/* Fix SR11 for 661 and later */
3673#ifdef CONFIG_FB_SIS_315
3674static void
3675sisfb_fixup_SR11(struct sis_video_info *ivideo)
3676{
3677        u8  tmpreg;
3678
3679        if(ivideo->chip >= SIS_661) {
3680                inSISIDXREG(SISSR,0x11,tmpreg);
3681                if(tmpreg & 0x20) {
3682                        inSISIDXREG(SISSR,0x3e,tmpreg);
3683                        tmpreg = (tmpreg + 1) & 0xff;
3684                        outSISIDXREG(SISSR,0x3e,tmpreg);
3685                        inSISIDXREG(SISSR,0x11,tmpreg);
3686                }
3687                if(tmpreg & 0xf0) {
3688                        andSISIDXREG(SISSR,0x11,0x0f);
3689                }
3690        }
3691}
3692#endif
3693
3694static void
3695sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3696{
3697        if(val > 32) val = 32;
3698        if(val < -32) val = -32;
3699        ivideo->tvxpos = val;
3700
3701        if(ivideo->sisfblocked) return;
3702        if(!ivideo->modechanged) return;
3703
3704        if(ivideo->currentvbflags & CRT2_TV) {
3705
3706                if(ivideo->vbflags2 & VB2_CHRONTEL) {
3707
3708                        int x = ivideo->tvx;
3709
3710                        switch(ivideo->chronteltype) {
3711                        case 1:
3712                                x += val;
3713                                if(x < 0) x = 0;
3714                                outSISIDXREG(SISSR,0x05,0x86);
3715                                SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3716                                SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3717                                break;
3718                        case 2:
3719                                /* Not supported by hardware */
3720                                break;
3721                        }
3722
3723                } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3724
3725                        u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3726                        unsigned short temp;
3727
3728                        p2_1f = ivideo->p2_1f;
3729                        p2_20 = ivideo->p2_20;
3730                        p2_2b = ivideo->p2_2b;
3731                        p2_42 = ivideo->p2_42;
3732                        p2_43 = ivideo->p2_43;
3733
3734                        temp = p2_1f | ((p2_20 & 0xf0) << 4);
3735                        temp += (val * 2);
3736                        p2_1f = temp & 0xff;
3737                        p2_20 = (temp & 0xf00) >> 4;
3738                        p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3739                        temp = p2_43 | ((p2_42 & 0xf0) << 4);
3740                        temp += (val * 2);
3741                        p2_43 = temp & 0xff;
3742                        p2_42 = (temp & 0xf00) >> 4;
3743                        outSISIDXREG(SISPART2,0x1f,p2_1f);
3744                        setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3745                        setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3746                        setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3747                        outSISIDXREG(SISPART2,0x43,p2_43);
3748                }
3749        }
3750}
3751
3752static void
3753sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3754{
3755        if(val > 32) val = 32;
3756        if(val < -32) val = -32;
3757        ivideo->tvypos = val;
3758
3759        if(ivideo->sisfblocked) return;
3760        if(!ivideo->modechanged) return;
3761
3762        if(ivideo->currentvbflags & CRT2_TV) {
3763
3764                if(ivideo->vbflags2 & VB2_CHRONTEL) {
3765
3766                        int y = ivideo->tvy;
3767
3768                        switch(ivideo->chronteltype) {
3769                        case 1:
3770                                y -= val;
3771                                if(y < 0) y = 0;
3772                                outSISIDXREG(SISSR,0x05,0x86);
3773                                SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3774                                SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3775                                break;
3776                        case 2:
3777                                /* Not supported by hardware */
3778                                break;
3779                        }
3780
3781                } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3782
3783                        char p2_01, p2_02;
3784                        val /= 2;
3785                        p2_01 = ivideo->p2_01;
3786                        p2_02 = ivideo->p2_02;
3787
3788                        p2_01 += val;
3789                        p2_02 += val;
3790                        if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3791                                while((p2_01 <= 0) || (p2_02 <= 0)) {
3792                                        p2_01 += 2;
3793                                        p2_02 += 2;
3794                                }
3795                        }
3796                        outSISIDXREG(SISPART2,0x01,p2_01);
3797                        outSISIDXREG(SISPART2,0x02,p2_02);
3798                }
3799        }
3800}
3801
3802static void
3803sisfb_post_setmode(struct sis_video_info *ivideo)
3804{
3805        bool crt1isoff = false;
3806        bool doit = true;
3807#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3808        u8 reg;
3809#endif
3810#ifdef CONFIG_FB_SIS_315
3811        u8 reg1;
3812#endif
3813
3814        outSISIDXREG(SISSR, 0x05, 0x86);
3815
3816#ifdef CONFIG_FB_SIS_315
3817        sisfb_fixup_SR11(ivideo);
3818#endif
3819
3820        /* Now we actually HAVE changed the display mode */
3821        ivideo->modechanged = 1;
3822
3823        /* We can't switch off CRT1 if bridge is in slave mode */
3824        if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3825                if(sisfb_bridgeisslave(ivideo)) doit = false;
3826        } else
3827                ivideo->sisfb_crt1off = 0;
3828
3829#ifdef CONFIG_FB_SIS_300
3830        if(ivideo->sisvga_engine == SIS_300_VGA) {
3831                if((ivideo->sisfb_crt1off) && (doit)) {
3832                        crt1isoff = true;
3833                        reg = 0x00;
3834                } else {
3835                        crt1isoff = false;
3836                        reg = 0x80;
3837                }
3838                setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3839        }
3840#endif
3841#ifdef CONFIG_FB_SIS_315
3842        if(ivideo->sisvga_engine == SIS_315_VGA) {
3843                if((ivideo->sisfb_crt1off) && (doit)) {
3844                        crt1isoff = true;
3845                        reg  = 0x40;
3846                        reg1 = 0xc0;
3847                } else {
3848                        crt1isoff = false;
3849                        reg  = 0x00;
3850                        reg1 = 0x00;
3851                }
3852                setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3853                setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3854        }
3855#endif
3856
3857        if(crt1isoff) {
3858                ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3859                ivideo->currentvbflags |= VB_SINGLE_MODE;
3860        } else {
3861                ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3862                if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3863                        ivideo->currentvbflags |= VB_MIRROR_MODE;
3864                } else {
3865                        ivideo->currentvbflags |= VB_SINGLE_MODE;
3866                }
3867        }
3868
3869        andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3870
3871        if(ivideo->currentvbflags & CRT2_TV) {
3872                if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3873                        inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3874                        inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3875                        inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3876                        inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3877                        inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3878                        inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3879                        inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3880                } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3881                        if(ivideo->chronteltype == 1) {
3882                                ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3883                                ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3884                                ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3885                                ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3886                        }
3887                }
3888        }
3889
3890        if(ivideo->tvxpos) {
3891                sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3892        }
3893        if(ivideo->tvypos) {
3894                sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3895        }
3896
3897        /* Eventually sync engines */
3898        sisfb_check_engine_and_sync(ivideo);
3899
3900        /* (Re-)Initialize chip engines */
3901        if(ivideo->accel) {
3902                sisfb_engine_init(ivideo);
3903        } else {
3904                ivideo->engineok = 0;
3905        }
3906}
3907
3908static int
3909sisfb_reset_mode(struct sis_video_info *ivideo)
3910{
3911        if(sisfb_set_mode(ivideo, 0))
3912                return 1;
3913
3914        sisfb_set_pitch(ivideo);
3915        sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3916        sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3917
3918        return 0;
3919}
3920
3921static void
3922sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3923{
3924        int mycrt1off;
3925
3926        switch(sisfb_command->sisfb_cmd) {
3927        case SISFB_CMD_GETVBFLAGS:
3928                if(!ivideo->modechanged) {
3929                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3930                } else {
3931                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3932                        sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3933                        sisfb_command->sisfb_result[2] = ivideo->vbflags2;
3934                }
3935                break;
3936        case SISFB_CMD_SWITCHCRT1:
3937                /* arg[0]: 0 = off, 1 = on, 99 = query */
3938                if(!ivideo->modechanged) {
3939                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3940                } else if(sisfb_command->sisfb_arg[0] == 99) {
3941                        /* Query */
3942                        sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3943                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3944                } else if(ivideo->sisfblocked) {
3945                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3946                } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3947                                        (sisfb_command->sisfb_arg[0] == 0)) {
3948                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3949                } else {
3950                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3951                        mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3952                        if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3953                            ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3954                                ivideo->sisfb_crt1off = mycrt1off;
3955                                if(sisfb_reset_mode(ivideo)) {
3956                                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
3957                                }
3958                        }
3959                        sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3960                }
3961                break;
3962        /* more to come */
3963        default:
3964                sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3965                printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3966                        sisfb_command->sisfb_cmd);
3967        }
3968}
3969
3970#ifndef MODULE
3971static int __init sisfb_setup(char *options)
3972{
3973        char *this_opt;
3974
3975        sisfb_setdefaultparms();
3976
3977        if(!options || !(*options))
3978                return 0;
3979
3980        while((this_opt = strsep(&options, ",")) != NULL) {
3981
3982                if(!(*this_opt)) continue;
3983
3984                if(!strnicmp(this_opt, "off", 3)) {
3985                        sisfb_off = 1;
3986                } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3987                        /* Need to check crt2 type first for fstn/dstn */
3988                        sisfb_search_crt2type(this_opt + 14);
3989                } else if(!strnicmp(this_opt, "tvmode:",7)) {
3990                        sisfb_search_tvstd(this_opt + 7);
3991                } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3992                        sisfb_search_tvstd(this_opt + 11);
3993                } else if(!strnicmp(this_opt, "mode:", 5)) {
3994                        sisfb_search_mode(this_opt + 5, false);
3995                } else if(!strnicmp(this_opt, "vesa:", 5)) {
3996                        sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
3997                } else if(!strnicmp(this_opt, "rate:", 5)) {
3998                        sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
3999                } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4000                        sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4001                } else if(!strnicmp(this_opt, "mem:",4)) {
4002                        sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4003                } else if(!strnicmp(this_opt, "pdc:", 4)) {
4004                        sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4005                } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4006                        sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4007                } else if(!strnicmp(this_opt, "noaccel", 7)) {
4008                        sisfb_accel = 0;
4009                } else if(!strnicmp(this_opt, "accel", 5)) {
4010                        sisfb_accel = -1;
4011                } else if(!strnicmp(this_opt, "noypan", 6)) {
4012                        sisfb_ypan = 0;
4013                } else if(!strnicmp(this_opt, "ypan", 4)) {
4014                        sisfb_ypan = -1;
4015                } else if(!strnicmp(this_opt, "nomax", 5)) {
4016                        sisfb_max = 0;
4017                } else if(!strnicmp(this_opt, "max", 3)) {
4018                        sisfb_max = -1;
4019                } else if(!strnicmp(this_opt, "userom:", 7)) {
4020                        sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4021                } else if(!strnicmp(this_opt, "useoem:", 7)) {
4022                        sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4023                } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4024                        sisfb_nocrt2rate = 1;
4025                } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4026                        unsigned long temp = 2;
4027                        temp = simple_strtoul(this_opt + 9, NULL, 0);
4028                        if((temp == 0) || (temp == 1)) {
4029                           sisfb_scalelcd = temp ^ 1;
4030                        }
4031                } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4032                        int temp = 0;
4033                        temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4034                        if((temp >= -32) && (temp <= 32)) {
4035                           sisfb_tvxposoffset = temp;
4036                        }
4037                } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4038                        int temp = 0;
4039                        temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4040                        if((temp >= -32) && (temp <= 32)) {
4041                           sisfb_tvyposoffset = temp;
4042                        }
4043                } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4044                        sisfb_search_specialtiming(this_opt + 14);
4045                } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4046                        int temp = 4;
4047                        temp = simple_strtoul(this_opt + 7, NULL, 0);
4048                        if((temp >= 0) && (temp <= 3)) {
4049                           sisfb_lvdshl = temp;
4050                        }
4051                } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4052                        sisfb_search_mode(this_opt, true);
4053#if !defined(__i386__) && !defined(__x86_64__)
4054                } else if(!strnicmp(this_opt, "resetcard", 9)) {
4055                        sisfb_resetcard = 1;
4056                } else if(!strnicmp(this_opt, "videoram:", 9)) {
4057                        sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4058#endif
4059                } else {
4060                        printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4061                }
4062
4063        }
4064
4065        return 0;
4066}
4067#endif
4068
4069static int __devinit
4070sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
4071{
4072        void __iomem *rom;
4073        int romptr;
4074
4075        if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4076                return 0;
4077
4078        romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4079        if(romptr > (0x10000 - 8))
4080                return 0;
4081
4082        rom = rom_base + romptr;
4083
4084        if((readb(rom)     != 'P') || (readb(rom + 1) != 'C') ||
4085           (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4086                return 0;
4087
4088        if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4089                return 0;
4090
4091        if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4092                return 0;
4093
4094        return 1;
4095}
4096
4097static unsigned char * __devinit
4098sisfb_find_rom(struct pci_dev *pdev)
4099{
4100        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4101        void __iomem *rom_base;
4102        unsigned char *myrombase = NULL;
4103        u32 temp;
4104        size_t romsize;
4105
4106        /* First, try the official pci ROM functions (except
4107         * on integrated chipsets which have no ROM).
4108         */
4109
4110        if(!ivideo->nbridge) {
4111
4112                if((rom_base = pci_map_rom(pdev, &romsize))) {
4113
4114                        if(sisfb_check_rom(rom_base, ivideo)) {
4115
4116                                if((myrombase = vmalloc(65536))) {
4117
4118                                        /* Work around bug in pci/rom.c: Folks forgot to check
4119                                         * whether the size retrieved from the BIOS image eventually
4120                                         * is larger than the mapped size
4121                                         */
4122                                        if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4123                                                romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4124
4125                                        memcpy_fromio(myrombase, rom_base,
4126                                                        (romsize > 65536) ? 65536 : romsize);
4127                                }
4128                        }
4129                        pci_unmap_rom(pdev, rom_base);
4130                }
4131        }
4132
4133        if(myrombase) return myrombase;
4134
4135        /* Otherwise do it the conventional way. */
4136
4137#if defined(__i386__) || defined(__x86_64__)
4138
4139        for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4140
4141                rom_base = ioremap(temp, 65536);
4142                if(!rom_base)
4143                        continue;
4144
4145                if(!sisfb_check_rom(rom_base, ivideo)) {
4146                        iounmap(rom_base);
4147                        continue;
4148                }
4149
4150                if((myrombase = vmalloc(65536)))
4151                        memcpy_fromio(myrombase, rom_base, 65536);
4152
4153                iounmap(rom_base);
4154                break;
4155
4156        }
4157
4158#else
4159
4160        pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4161        pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4162                        (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4163
4164        rom_base = ioremap(ivideo->video_base, 65536);
4165        if(rom_base) {
4166                if(sisfb_check_rom(rom_base, ivideo)) {
4167                        if((myrombase = vmalloc(65536)))
4168                                memcpy_fromio(myrombase, rom_base, 65536);
4169                }
4170                iounmap(rom_base);
4171        }
4172
4173        pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4174
4175#endif
4176
4177        return myrombase;
4178}
4179
4180static void __devinit
4181sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4182                        unsigned int min)
4183{
4184        ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4185
4186        if(!ivideo->video_vbase) {
4187                printk(KERN_ERR
4188                        "sisfb: Unable to map maximum video RAM for size detection\n");
4189                (*mapsize) >>= 1;
4190                while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4191                        (*mapsize) >>= 1;
4192                        if((*mapsize) < (min << 20))
4193                                break;
4194                }
4195                if(ivideo->video_vbase) {
4196                        printk(KERN_ERR
4197                                "sisfb: Video RAM size detection limited to %dMB\n",
4198                                (int)((*mapsize) >> 20));
4199                }
4200        }
4201}
4202
4203#ifdef CONFIG_FB_SIS_300
4204static int __devinit
4205sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4206{
4207        void __iomem *FBAddress = ivideo->video_vbase;
4208        unsigned short temp;
4209        unsigned char reg;
4210        int i, j;
4211
4212        andSISIDXREG(SISSR, 0x15, 0xFB);
4213        orSISIDXREG(SISSR, 0x15, 0x04);
4214        outSISIDXREG(SISSR, 0x13, 0x00);
4215        outSISIDXREG(SISSR, 0x14, 0xBF);
4216
4217        for(i = 0; i < 2; i++) {
4218                temp = 0x1234;
4219                for(j = 0; j < 4; j++) {
4220                        writew(temp, FBAddress);
4221                        if(readw(FBAddress) == temp)
4222                                break;
4223                        orSISIDXREG(SISSR, 0x3c, 0x01);
4224                        inSISIDXREG(SISSR, 0x05, reg);
4225                        inSISIDXREG(SISSR, 0x05, reg);
4226                        andSISIDXREG(SISSR, 0x3c, 0xfe);
4227                        inSISIDXREG(SISSR, 0x05, reg);
4228                        inSISIDXREG(SISSR, 0x05, reg);
4229                        temp++;
4230                }
4231        }
4232
4233        writel(0x01234567L, FBAddress);
4234        writel(0x456789ABL, (FBAddress + 4));
4235        writel(0x89ABCDEFL, (FBAddress + 8));
4236        writel(0xCDEF0123L, (FBAddress + 12));
4237
4238        inSISIDXREG(SISSR, 0x3b, reg);
4239        if(reg & 0x01) {
4240                if(readl((FBAddress + 12)) == 0xCDEF0123L)
4241                        return 4;       /* Channel A 128bit */
4242        }
4243
4244        if(readl((FBAddress + 4)) == 0x456789ABL)
4245                return 2;               /* Channel B 64bit */
4246
4247        return 1;                       /* 32bit */
4248}
4249
4250static int __devinit
4251sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4252                        int PseudoRankCapacity, int PseudoAdrPinCount,
4253                        unsigned int mapsize)
4254{
4255        void __iomem *FBAddr = ivideo->video_vbase;
4256        unsigned short sr14;
4257        unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4258        unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4259        static const unsigned short SiS_DRAMType[17][5] = {
4260                {0x0C,0x0A,0x02,0x40,0x39},
4261                {0x0D,0x0A,0x01,0x40,0x48},
4262                {0x0C,0x09,0x02,0x20,0x35},
4263                {0x0D,0x09,0x01,0x20,0x44},
4264                {0x0C,0x08,0x02,0x10,0x31},
4265                {0x0D,0x08,0x01,0x10,0x40},
4266                {0x0C,0x0A,0x01,0x20,0x34},
4267                {0x0C,0x09,0x01,0x08,0x32},
4268                {0x0B,0x08,0x02,0x08,0x21},
4269                {0x0C,0x08,0x01,0x08,0x30},
4270                {0x0A,0x08,0x02,0x04,0x11},
4271                {0x0B,0x0A,0x01,0x10,0x28},
4272                {0x09,0x08,0x02,0x02,0x01},
4273                {0x0B,0x09,0x01,0x08,0x24},
4274                {0x0B,0x08,0x01,0x04,0x20},
4275                {0x0A,0x08,0x01,0x02,0x10},
4276                {0x09,0x08,0x01,0x01,0x00}
4277        };
4278
4279         for(k = 0; k <= 16; k++) {
4280
4281                RankCapacity = buswidth * SiS_DRAMType[k][3];
4282
4283                if(RankCapacity != PseudoRankCapacity)
4284                        continue;
4285
4286                if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4287                        continue;
4288
4289                BankNumHigh = RankCapacity * 16 * iteration - 1;
4290                if(iteration == 3) {             /* Rank No */
4291                        BankNumMid  = RankCapacity * 16 - 1;
4292                } else {
4293                        BankNumMid  = RankCapacity * 16 * iteration / 2 - 1;
4294                }
4295
4296                PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4297                PhysicalAdrHigh = BankNumHigh;
4298                PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4299                PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4300
4301                andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4302                orSISIDXREG(SISSR, 0x15, 0x04);  /* Test */
4303                sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4304                if(buswidth == 4)      sr14 |= 0x80;
4305                else if(buswidth == 2) sr14 |= 0x40;
4306                outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4307                outSISIDXREG(SISSR, 0x14, sr14);
4308
4309                BankNumHigh <<= 16;
4310                BankNumMid <<= 16;
4311
4312                if((BankNumHigh + PhysicalAdrHigh      >= mapsize) ||
4313                   (BankNumMid  + PhysicalAdrHigh      >= mapsize) ||
4314                   (BankNumHigh + PhysicalAdrHalfPage  >= mapsize) ||
4315                   (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4316                        continue;
4317
4318                /* Write data */
4319                writew(((unsigned short)PhysicalAdrHigh),
4320                                (FBAddr + BankNumHigh + PhysicalAdrHigh));
4321                writew(((unsigned short)BankNumMid),
4322                                (FBAddr + BankNumMid  + PhysicalAdrHigh));
4323                writew(((unsigned short)PhysicalAdrHalfPage),
4324                                (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4325                writew(((unsigned short)PhysicalAdrOtherPage),
4326                                (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4327
4328                /* Read data */
4329                if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4330                        return 1;
4331        }
4332
4333        return 0;
4334}
4335
4336static void __devinit
4337sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4338{
4339        struct  sis_video_info *ivideo = pci_get_drvdata(pdev);
4340        int     i, j, buswidth;
4341        int     PseudoRankCapacity, PseudoAdrPinCount;
4342
4343        buswidth = sisfb_post_300_buswidth(ivideo);
4344
4345        for(i = 6; i >= 0; i--) {
4346                PseudoRankCapacity = 1 << i;
4347                for(j = 4; j >= 1; j--) {
4348                        PseudoAdrPinCount = 15 - j;
4349                        if((PseudoRankCapacity * j) <= 64) {
4350                                if(sisfb_post_300_rwtest(ivideo,
4351                                                j,
4352                                                buswidth,
4353                                                PseudoRankCapacity,
4354                                                PseudoAdrPinCount,
4355                                                mapsize))
4356                                        return;
4357                        }
4358                }
4359        }
4360}
4361
4362static void __devinit
4363sisfb_post_sis300(struct pci_dev *pdev)
4364{
4365        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4366        unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4367        u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
4368        u16 index, rindex, memtype = 0;
4369        unsigned int mapsize;
4370
4371        if(!ivideo->SiS_Pr.UseROM)
4372                bios = NULL;
4373
4374        outSISIDXREG(SISSR, 0x05, 0x86);
4375
4376        if(bios) {
4377                if(bios[0x52] & 0x80) {
4378                        memtype = bios[0x52];
4379                } else {
4380                        inSISIDXREG(SISSR, 0x3a, memtype);
4381                }
4382                memtype &= 0x07;
4383        }
4384
4385        v3 = 0x80; v6 = 0x80;
4386        if(ivideo->revision_id <= 0x13) {
4387                v1 = 0x44; v2 = 0x42;
4388                v4 = 0x44; v5 = 0x42;
4389        } else {
4390                v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4391                v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4392                if(bios) {
4393                        index = memtype * 5;
4394                        rindex = index + 0x54;
4395                        v1 = bios[rindex++];
4396                        v2 = bios[rindex++];
4397                        v3 = bios[rindex++];
4398                        rindex = index + 0x7c;
4399                        v4 = bios[rindex++];
4400                        v5 = bios[rindex++];
4401                        v6 = bios[rindex++];
4402                }
4403        }
4404        outSISIDXREG(SISSR, 0x28, v1);
4405        outSISIDXREG(SISSR, 0x29, v2);
4406        outSISIDXREG(SISSR, 0x2a, v3);
4407        outSISIDXREG(SISSR, 0x2e, v4);
4408        outSISIDXREG(SISSR, 0x2f, v5);
4409        outSISIDXREG(SISSR, 0x30, v6);
4410
4411        v1 = 0x10;
4412        if(bios)
4413                v1 = bios[0xa4];
4414        outSISIDXREG(SISSR, 0x07, v1);       /* DAC speed */
4415
4416        outSISIDXREG(SISSR, 0x11, 0x0f);     /* DDC, power save */
4417
4418        v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4419        v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4420        if(bios) {
4421                memtype += 0xa5;
4422                v1 = bios[memtype];
4423                v2 = bios[memtype + 8];
4424                v3 = bios[memtype + 16];
4425                v4 = bios[memtype + 24];
4426                v5 = bios[memtype + 32];
4427                v6 = bios[memtype + 40];
4428                v7 = bios[memtype + 48];
4429                v8 = bios[memtype + 56];
4430        }
4431        if(ivideo->revision_id >= 0x80)
4432                v3 &= 0xfd;
4433        outSISIDXREG(SISSR, 0x15, v1);       /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4434        outSISIDXREG(SISSR, 0x16, v2);
4435        outSISIDXREG(SISSR, 0x17, v3);
4436        outSISIDXREG(SISSR, 0x18, v4);
4437        outSISIDXREG(SISSR, 0x19, v5);
4438        outSISIDXREG(SISSR, 0x1a, v6);
4439        outSISIDXREG(SISSR, 0x1b, v7);
4440        outSISIDXREG(SISSR, 0x1c, v8);     /* ---- */
4441        andSISIDXREG(SISSR, 0x15 ,0xfb);
4442        orSISIDXREG(SISSR, 0x15, 0x04);
4443        if(bios) {
4444                if(bios[0x53] & 0x02) {
4445                        orSISIDXREG(SISSR, 0x19, 0x20);
4446                }
4447        }
4448        v1 = 0x04;                         /* DAC pedestal (BIOS 0xe5) */
4449        if(ivideo->revision_id >= 0x80)
4450                v1 |= 0x01;
4451        outSISIDXREG(SISSR, 0x1f, v1);
4452        outSISIDXREG(SISSR, 0x20, 0xa4);     /* linear & relocated io & disable a0000 */
4453        v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4454        if(bios) {
4455                v1 = bios[0xe8];
4456                v2 = bios[0xe9];
4457                v3 = bios[0xea];
4458        }
4459        outSISIDXREG(SISSR, 0x23, v1);
4460        outSISIDXREG(SISSR, 0x24, v2);
4461        outSISIDXREG(SISSR, 0x25, v3);
4462        outSISIDXREG(SISSR, 0x21, 0x84);
4463        outSISIDXREG(SISSR, 0x22, 0x00);
4464        outSISIDXREG(SISCR, 0x37, 0x00);
4465        orSISIDXREG(SISPART1, 0x24, 0x01);   /* unlock crt2 */
4466        outSISIDXREG(SISPART1, 0x00, 0x00);
4467        v1 = 0x40; v2 = 0x11;
4468        if(bios) {
4469                v1 = bios[0xec];
4470                v2 = bios[0xeb];
4471        }
4472        outSISIDXREG(SISPART1, 0x02, v1);
4473
4474        if(ivideo->revision_id >= 0x80)
4475                v2 &= ~0x01;
4476
4477        inSISIDXREG(SISPART4, 0x00, reg);
4478        if((reg == 1) || (reg == 2)) {
4479                outSISIDXREG(SISCR, 0x37, 0x02);
4480                outSISIDXREG(SISPART2, 0x00, 0x1c);
4481                v4 = 0x00; v5 = 0x00; v6 = 0x10;
4482                if(ivideo->SiS_Pr.UseROM) {
4483                        v4 = bios[0xf5];
4484                        v5 = bios[0xf6];
4485                        v6 = bios[0xf7];
4486                }
4487                outSISIDXREG(SISPART4, 0x0d, v4);
4488                outSISIDXREG(SISPART4, 0x0e, v5);
4489                outSISIDXREG(SISPART4, 0x10, v6);
4490                outSISIDXREG(SISPART4, 0x0f, 0x3f);
4491                inSISIDXREG(SISPART4, 0x01, reg);
4492                if(reg >= 0xb0) {
4493                        inSISIDXREG(SISPART4, 0x23, reg);
4494                        reg &= 0x20;
4495                        reg <<= 1;
4496                        outSISIDXREG(SISPART4, 0x23, reg);
4497                }
4498        } else {
4499                v2 &= ~0x10;
4500        }
4501        outSISIDXREG(SISSR, 0x32, v2);
4502
4503        andSISIDXREG(SISPART1, 0x24, 0xfe);  /* Lock CRT2 */
4504
4505        inSISIDXREG(SISSR, 0x16, reg);
4506        reg &= 0xc3;
4507        outSISIDXREG(SISCR, 0x35, reg);
4508        outSISIDXREG(SISCR, 0x83, 0x00);
4509#if !defined(__i386__) && !defined(__x86_64__)
4510        if(sisfb_videoram) {
4511                outSISIDXREG(SISSR, 0x13, 0x28);  /* ? */
4512                reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4513                outSISIDXREG(SISSR, 0x14, reg);
4514        } else {
4515#endif
4516                /* Need to map max FB size for finding out about RAM size */
4517                mapsize = 64 << 20;
4518                sisfb_post_map_vram(ivideo, &mapsize, 4);
4519
4520                if(ivideo->video_vbase) {
4521                        sisfb_post_300_ramsize(pdev, mapsize);
4522                        iounmap(ivideo->video_vbase);
4523                } else {
4524                        printk(KERN_DEBUG
4525                                "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4526                        outSISIDXREG(SISSR, 0x13, 0x28);  /* ? */
4527                        outSISIDXREG(SISSR, 0x14, 0x47);  /* 8MB, 64bit default */
4528                }
4529#if !defined(__i386__) && !defined(__x86_64__)
4530        }
4531#endif
4532        if(bios) {
4533                v1 = bios[0xe6];
4534                v2 = bios[0xe7];
4535        } else {
4536                inSISIDXREG(SISSR, 0x3a, reg);
4537                if((reg & 0x30) == 0x30) {
4538                        v1 = 0x04; /* PCI */
4539                        v2 = 0x92;
4540                } else {
4541                        v1 = 0x14; /* AGP */
4542                        v2 = 0xb2;
4543                }
4544        }
4545        outSISIDXREG(SISSR, 0x21, v1);
4546        outSISIDXREG(SISSR, 0x22, v2);
4547
4548        /* Sense CRT1 */
4549        sisfb_sense_crt1(ivideo);
4550
4551        /* Set default mode, don't clear screen */
4552        ivideo->SiS_Pr.SiS_UseOEM = false;
4553        SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4554        SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
4555        ivideo->curFSTN = ivideo->curDSTN = 0;
4556        ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4557        SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4558
4559        outSISIDXREG(SISSR, 0x05, 0x86);
4560
4561        /* Display off */
4562        orSISIDXREG(SISSR, 0x01, 0x20);
4563
4564        /* Save mode number in CR34 */
4565        outSISIDXREG(SISCR, 0x34, 0x2e);
4566
4567        /* Let everyone know what the current mode is */
4568        ivideo->modeprechange = 0x2e;
4569}
4570#endif
4571
4572#ifdef CONFIG_FB_SIS_315
4573#if 0
4574static void __devinit
4575sisfb_post_sis315330(struct pci_dev *pdev)
4576{
4577        /* TODO */
4578}
4579#endif
4580
4581static void __devinit
4582sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4583{
4584        unsigned int i;
4585        u8 reg;
4586
4587        for(i = 0; i <= (delay * 10 * 36); i++) {
4588                inSISIDXREG(SISSR, 0x05, reg);
4589                reg++;
4590        }
4591}
4592
4593static int __devinit
4594sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4595                                unsigned short pcivendor)
4596{
4597        struct pci_dev *pdev = NULL;
4598        unsigned short temp;
4599        int ret = 0;
4600
4601        while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
4602                temp = pdev->vendor;
4603                if(temp == pcivendor) {
4604                        ret = 1;
4605                        pci_dev_put(pdev);
4606                        break;
4607                }
4608        }
4609
4610        return ret;
4611}
4612
4613static int __devinit
4614sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4615                        unsigned int enda, unsigned int mapsize)
4616{
4617        unsigned int pos;
4618        int i;
4619
4620        writel(0, ivideo->video_vbase);
4621
4622        for(i = starta; i <= enda; i++) {
4623                pos = 1 << i;
4624                if(pos < mapsize)
4625                        writel(pos, ivideo->video_vbase + pos);
4626        }
4627
4628        sisfb_post_xgi_delay(ivideo, 150);
4629
4630        if(readl(ivideo->video_vbase) != 0)
4631                return 0;
4632
4633        for(i = starta; i <= enda; i++) {
4634                pos = 1 << i;
4635                if(pos < mapsize) {
4636                        if(readl(ivideo->video_vbase + pos) != pos)
4637                                return 0;
4638                } else
4639                        return 0;
4640        }
4641
4642        return 1;
4643}
4644
4645static void __devinit
4646sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4647{
4648        unsigned int buswidth, ranksize, channelab, mapsize;
4649        int i, j, k, l;
4650        u8 reg, sr14;
4651        static const u8 dramsr13[12 * 5] = {
4652                0x02, 0x0e, 0x0b, 0x80, 0x5d,
4653                0x02, 0x0e, 0x0a, 0x40, 0x59,
4654                0x02, 0x0d, 0x0b, 0x40, 0x4d,
4655                0x02, 0x0e, 0x09, 0x20, 0x55,
4656                0x02, 0x0d, 0x0a, 0x20, 0x49,
4657                0x02, 0x0c, 0x0b, 0x20, 0x3d,
4658                0x02, 0x0e, 0x08, 0x10, 0x51,
4659                0x02, 0x0d, 0x09, 0x10, 0x45,
4660                0x02, 0x0c, 0x0a, 0x10, 0x39,
4661                0x02, 0x0d, 0x08, 0x08, 0x41,
4662                0x02, 0x0c, 0x09, 0x08, 0x35,
4663                0x02, 0x0c, 0x08, 0x04, 0x31
4664        };
4665        static const u8 dramsr13_4[4 * 5] = {
4666                0x02, 0x0d, 0x09, 0x40, 0x45,
4667                0x02, 0x0c, 0x09, 0x20, 0x35,
4668                0x02, 0x0c, 0x08, 0x10, 0x31,
4669                0x02, 0x0b, 0x08, 0x08, 0x21
4670        };
4671
4672        /* Enable linear mode, disable 0xa0000 address decoding */
4673        /* We disable a0000 address decoding, because
4674         * - if running on x86, if the card is disabled, it means
4675         *   that another card is in the system. We don't want
4676         *   to interphere with that primary card's textmode.
4677         * - if running on non-x86, there usually is no VGA window
4678         *   at a0000.
4679         */
4680        orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4681
4682        /* Need to map max FB size for finding out about RAM size */
4683        mapsize = 256 << 20;
4684        sisfb_post_map_vram(ivideo, &mapsize, 32);
4685
4686        if(!ivideo->video_vbase) {
4687                printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4688                outSISIDXREG(SISSR, 0x13, 0x35);
4689                outSISIDXREG(SISSR, 0x14, 0x41);
4690                /* TODO */
4691                return;
4692        }
4693
4694        /* Non-interleaving */
4695        outSISIDXREG(SISSR, 0x15, 0x00);
4696        /* No tiling */
4697        outSISIDXREG(SISSR, 0x1c, 0x00);
4698
4699        if(ivideo->chip == XGI_20) {
4700
4701                channelab = 1;
4702                inSISIDXREG(SISCR, 0x97, reg);
4703                if(!(reg & 0x01)) {     /* Single 32/16 */
4704                        buswidth = 32;
4705                        outSISIDXREG(SISSR, 0x13, 0xb1);
4706                        outSISIDXREG(SISSR, 0x14, 0x52);
4707                        sisfb_post_xgi_delay(ivideo, 1);
4708                        sr14 = 0x02;
4709                        if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4710                                goto bail_out;
4711
4712                        outSISIDXREG(SISSR, 0x13, 0x31);
4713                        outSISIDXREG(SISSR, 0x14, 0x42);
4714                        sisfb_post_xgi_delay(ivideo, 1);
4715                        if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4716                                goto bail_out;
4717
4718                        buswidth = 16;
4719                        outSISIDXREG(SISSR, 0x13, 0xb1);
4720                        outSISIDXREG(SISSR, 0x14, 0x41);
4721                        sisfb_post_xgi_delay(ivideo, 1);
4722                        sr14 = 0x01;
4723                        if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4724                                goto bail_out;
4725                        else
4726                                outSISIDXREG(SISSR, 0x13, 0x31);
4727                } else {                /* Dual 16/8 */
4728                        buswidth = 16;
4729                        outSISIDXREG(SISSR, 0x13, 0xb1);
4730                        outSISIDXREG(SISSR, 0x14, 0x41);
4731                        sisfb_post_xgi_delay(ivideo, 1);
4732                        sr14 = 0x01;
4733                        if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4734                                goto bail_out;
4735
4736                        outSISIDXREG(SISSR, 0x13, 0x31);
4737                        outSISIDXREG(SISSR, 0x14, 0x31);
4738                        sisfb_post_xgi_delay(ivideo, 1);
4739                        if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4740                                goto bail_out;
4741
4742                        buswidth = 8;
4743                        outSISIDXREG(SISSR, 0x13, 0xb1);
4744                        outSISIDXREG(SISSR, 0x14, 0x30);
4745                        sisfb_post_xgi_delay(ivideo, 1);
4746                        sr14 = 0x00;
4747                        if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4748                                goto bail_out;
4749                        else
4750                                outSISIDXREG(SISSR, 0x13, 0x31);
4751                }
4752
4753        } else {        /* XGI_40 */
4754
4755                inSISIDXREG(SISCR, 0x97, reg);
4756                if(!(reg & 0x10)) {
4757                        inSISIDXREG(SISSR, 0x39, reg);
4758                        reg >>= 1;
4759                }
4760
4761                if(reg & 0x01) {        /* DDRII */
4762                        buswidth = 32;
4763                        if(ivideo->revision_id == 2) {
4764                                channelab = 2;
4765                                outSISIDXREG(SISSR, 0x13, 0xa1);
4766                                outSISIDXREG(SISSR, 0x14, 0x44);
4767                                sr14 = 0x04;
4768                                sisfb_post_xgi_delay(ivideo, 1);
4769                                if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4770                                        goto bail_out;
4771
4772                                outSISIDXREG(SISSR, 0x13, 0x21);
4773                                outSISIDXREG(SISSR, 0x14, 0x34);
4774                                if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4775                                        goto bail_out;
4776
4777                                channelab = 1;
4778                                outSISIDXREG(SISSR, 0x13, 0xa1);
4779                                outSISIDXREG(SISSR, 0x14, 0x40);
4780                                sr14 = 0x00;
4781                                if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4782                                        goto bail_out;
4783
4784                                outSISIDXREG(SISSR, 0x13, 0x21);
4785                                outSISIDXREG(SISSR, 0x14, 0x30);
4786                        } else {
4787                                channelab = 3;
4788                                outSISIDXREG(SISSR, 0x13, 0xa1);
4789                                outSISIDXREG(SISSR, 0x14, 0x4c);
4790                                sr14 = 0x0c;
4791                                sisfb_post_xgi_delay(ivideo, 1);
4792                                if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4793                                        goto bail_out;
4794
4795                                channelab = 2;
4796                                outSISIDXREG(SISSR, 0x14, 0x48);
4797                                sisfb_post_xgi_delay(ivideo, 1);
4798                                sr14 = 0x08;
4799                                if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4800                                        goto bail_out;
4801
4802                                outSISIDXREG(SISSR, 0x13, 0x21);
4803                                outSISIDXREG(SISSR, 0x14, 0x3c);
4804                                sr14 = 0x0c;
4805
4806                                if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4807                                        channelab = 3;
4808                                } else {
4809                                        channelab = 2;
4810                                        outSISIDXREG(SISSR, 0x14, 0x38);
4811                                        sr14 = 0x08;
4812                                }
4813                        }
4814                        sisfb_post_xgi_delay(ivideo, 1);
4815
4816                } else {        /* DDR */
4817
4818                        buswidth = 64;
4819                        if(ivideo->revision_id == 2) {
4820                                channelab = 1;
4821                                outSISIDXREG(SISSR, 0x13, 0xa1);
4822                                outSISIDXREG(SISSR, 0x14, 0x52);
4823                                sisfb_post_xgi_delay(ivideo, 1);
4824                                sr14 = 0x02;
4825                                if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4826                                        goto bail_out;
4827
4828                                outSISIDXREG(SISSR, 0x13, 0x21);
4829                                outSISIDXREG(SISSR, 0x14, 0x42);
4830                        } else {
4831                                channelab = 2;
4832                                outSISIDXREG(SISSR, 0x13, 0xa1);
4833                                outSISIDXREG(SISSR, 0x14, 0x5a);
4834                                sisfb_post_xgi_delay(ivideo, 1);
4835                                sr14 = 0x0a;
4836                                if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4837                                        goto bail_out;
4838
4839                                outSISIDXREG(SISSR, 0x13, 0x21);
4840                                outSISIDXREG(SISSR, 0x14, 0x4a);
4841                        }
4842                        sisfb_post_xgi_delay(ivideo, 1);
4843
4844                }
4845        }
4846
4847bail_out:
4848        setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4849        sisfb_post_xgi_delay(ivideo, 1);
4850
4851        j = (ivideo->chip == XGI_20) ? 5 : 9;
4852        k = (ivideo->chip == XGI_20) ? 12 : 4;
4853
4854        for(i = 0; i < k; i++) {
4855
4856                reg = (ivideo->chip == XGI_20) ?
4857                                dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4858                setSISIDXREG(SISSR, 0x13, 0x80, reg);
4859                sisfb_post_xgi_delay(ivideo, 50);
4860
4861                ranksize = (ivideo->chip == XGI_20) ?
4862                                dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4863
4864                inSISIDXREG(SISSR, 0x13, reg);
4865                if(reg & 0x80) ranksize <<= 1;
4866
4867                if(ivideo->chip == XGI_20) {
4868                        if(buswidth == 16)      ranksize <<= 1;
4869                        else if(buswidth == 32) ranksize <<= 2;
4870                } else {
4871                        if(buswidth == 64)      ranksize <<= 1;
4872                }
4873
4874                reg = 0;
4875                l = channelab;
4876                if(l == 3) l = 4;
4877                if((ranksize * l) <= 256) {
4878                        while((ranksize >>= 1)) reg += 0x10;
4879                }
4880
4881                if(!reg) continue;
4882
4883                setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4884                sisfb_post_xgi_delay(ivideo, 1);
4885
4886                if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4887                        break;
4888        }
4889
4890        iounmap(ivideo->video_vbase);
4891}
4892
4893static void __devinit
4894sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4895{
4896        u8 v1, v2, v3;
4897        int index;
4898        static const u8 cs90[8 * 3] = {
4899                0x16, 0x01, 0x01,
4900                0x3e, 0x03, 0x01,
4901                0x7c, 0x08, 0x01,
4902                0x79, 0x06, 0x01,
4903                0x29, 0x01, 0x81,
4904                0x5c, 0x23, 0x01,
4905                0x5c, 0x23, 0x01,
4906                0x5c, 0x23, 0x01
4907        };
4908        static const u8 csb8[8 * 3] = {
4909                0x5c, 0x23, 0x01,
4910                0x29, 0x01, 0x01,
4911                0x7c, 0x08, 0x01,
4912                0x79, 0x06, 0x01,
4913                0x29, 0x01, 0x81,
4914                0x5c, 0x23, 0x01,
4915                0x5c, 0x23, 0x01,
4916                0x5c, 0x23, 0x01
4917        };
4918
4919        regb = 0;  /* ! */
4920
4921        index = regb * 3;
4922        v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4923        if(ivideo->haveXGIROM) {
4924                v1 = ivideo->bios_abase[0x90 + index];
4925                v2 = ivideo->bios_abase[0x90 + index + 1];
4926                v3 = ivideo->bios_abase[0x90 + index + 2];
4927        }
4928        outSISIDXREG(SISSR, 0x28, v1);
4929        outSISIDXREG(SISSR, 0x29, v2);
4930        outSISIDXREG(SISSR, 0x2a, v3);
4931        sisfb_post_xgi_delay(ivideo, 0x43);
4932        sisfb_post_xgi_delay(ivideo, 0x43);
4933        sisfb_post_xgi_delay(ivideo, 0x43);
4934        index = regb * 3;
4935        v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4936        if(ivideo->haveXGIROM) {
4937                v1 = ivideo->bios_abase[0xb8 + index];
4938                v2 = ivideo->bios_abase[0xb8 + index + 1];
4939                v3 = ivideo->bios_abase[0xb8 + index + 2];
4940        }
4941        outSISIDXREG(SISSR, 0x2e, v1);
4942        outSISIDXREG(SISSR, 0x2f, v2);
4943        outSISIDXREG(SISSR, 0x30, v3);
4944        sisfb_post_xgi_delay(ivideo, 0x43);
4945        sisfb_post_xgi_delay(ivideo, 0x43);
4946        sisfb_post_xgi_delay(ivideo, 0x43);
4947}
4948
4949static int __devinit
4950sisfb_post_xgi(struct pci_dev *pdev)
4951{
4952        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4953        unsigned char *bios = ivideo->bios_abase;
4954        struct pci_dev *mypdev = NULL;
4955        const u8 *ptr, *ptr2;
4956        u8 v1, v2, v3, v4, v5, reg, ramtype;
4957        u32 rega, regb, regd;
4958        int i, j, k, index;
4959        static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4960        static const u8 cs76[2] = { 0xa3, 0xfb };
4961        static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4962        static const u8 cs158[8] = {
4963                0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4964        };
4965        static const u8 cs160[8] = {
4966                0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4967        };
4968        static const u8 cs168[8] = {
4969                0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4970        };
4971        static const u8 cs128[3 * 8] = {
4972                0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4973                0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4974                0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4975        };
4976        static const u8 cs148[2 * 8] = {
4977                0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4978                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4979        };
4980        static const u8 cs31a[8 * 4] = {
4981                0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
4982                0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
4983                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4984                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4985        };
4986        static const u8 cs33a[8 * 4] = {
4987                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4988                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4989                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4990                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4991        };
4992        static const u8 cs45a[8 * 2] = {
4993                0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
4994                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4995        };
4996        static const u8 cs170[7 * 8] = {
4997                0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4998                0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4999                0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5000                0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5001                0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5002                0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5003                0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5004        };
5005        static const u8 cs1a8[3 * 8] = {
5006                0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5007                0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5008                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5009        };
5010        static const u8 cs100[2 * 8] = {
5011                0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5012                0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5013        };
5014
5015        /* VGA enable */
5016        reg = inSISREG(SISVGAENABLE) | 0x01;
5017        outSISREG(SISVGAENABLE, reg);
5018
5019        /* Misc */
5020        reg = inSISREG(SISMISCR) | 0x01;
5021        outSISREG(SISMISCW, reg);
5022
5023        /* Unlock SR */
5024        outSISIDXREG(SISSR, 0x05, 0x86);
5025        inSISIDXREG(SISSR, 0x05, reg);
5026        if(reg != 0xa1)
5027                return 0;
5028
5029        /* Clear some regs */
5030        for(i = 0; i < 0x22; i++) {
5031                if(0x06 + i == 0x20) continue;
5032                outSISIDXREG(SISSR, 0x06 + i, 0x00);
5033        }
5034        for(i = 0; i < 0x0b; i++) {
5035                outSISIDXREG(SISSR, 0x31 + i, 0x00);
5036        }
5037        for(i = 0; i < 0x10; i++) {
5038                outSISIDXREG(SISCR, 0x30 + i, 0x00);
5039        }
5040
5041        ptr = cs78;
5042        if(ivideo->haveXGIROM) {
5043                ptr = (const u8 *)&bios[0x78];
5044        }
5045        for(i = 0; i < 3; i++) {
5046                outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5047        }
5048
5049        ptr = cs76;
5050        if(ivideo->haveXGIROM) {
5051                ptr = (const u8 *)&bios[0x76];
5052        }
5053        for(i = 0; i < 2; i++) {
5054                outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5055        }
5056
5057        v1 = 0x18; v2 = 0x00;
5058        if(ivideo->haveXGIROM) {
5059                v1 = bios[0x74];
5060                v2 = bios[0x75];
5061        }
5062        outSISIDXREG(SISSR, 0x07, v1);
5063        outSISIDXREG(SISSR, 0x11, 0x0f);
5064        outSISIDXREG(SISSR, 0x1f, v2);
5065        /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5066        outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5067        outSISIDXREG(SISSR, 0x27, 0x74);
5068
5069        ptr = cs7b;
5070        if(ivideo->haveXGIROM) {
5071                ptr = (const u8 *)&bios[0x7b];
5072        }
5073        for(i = 0; i < 3; i++) {
5074                outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5075        }
5076
5077        if(ivideo->chip == XGI_40) {
5078                if(ivideo->revision_id == 2) {
5079                        setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5080                }
5081                outSISIDXREG(SISCR, 0x7d, 0xfe);
5082                outSISIDXREG(SISCR, 0x7e, 0x0f);
5083        }
5084        if(ivideo->revision_id == 0) {  /* 40 *and* 20? */
5085                andSISIDXREG(SISCR, 0x58, 0xd7);
5086                inSISIDXREG(SISCR, 0xcb, reg);
5087                if(reg & 0x20) {
5088                        setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5089                }
5090        }
5091
5092        reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5093        setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5094
5095        if(ivideo->chip == XGI_20) {
5096                outSISIDXREG(SISSR, 0x36, 0x70);
5097        } else {
5098                outSISIDXREG(SISVID, 0x00, 0x86);
5099                outSISIDXREG(SISVID, 0x32, 0x00);
5100                outSISIDXREG(SISVID, 0x30, 0x00);
5101                outSISIDXREG(SISVID, 0x32, 0x01);
5102                outSISIDXREG(SISVID, 0x30, 0x00);
5103                andSISIDXREG(SISVID, 0x2f, 0xdf);
5104                andSISIDXREG(SISCAP, 0x00, 0x3f);
5105
5106                outSISIDXREG(SISPART1, 0x2f, 0x01);
5107                outSISIDXREG(SISPART1, 0x00, 0x00);
5108                outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5109                outSISIDXREG(SISPART1, 0x2e, 0x08);
5110                andSISIDXREG(SISPART1, 0x35, 0x7f);
5111                andSISIDXREG(SISPART1, 0x50, 0xfe);
5112
5113                inSISIDXREG(SISPART4, 0x00, reg);
5114                if(reg == 1 || reg == 2) {
5115                        outSISIDXREG(SISPART2, 0x00, 0x1c);
5116                        outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5117                        outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5118                        outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5119                        andSISIDXREG(SISPART4, 0x0f, 0x3f);
5120
5121                        inSISIDXREG(SISPART4, 0x01, reg);
5122                        if((reg & 0xf0) >= 0xb0) {
5123                                inSISIDXREG(SISPART4, 0x23, reg);
5124                                if(reg & 0x20) reg |= 0x40;
5125                                outSISIDXREG(SISPART4, 0x23, reg);
5126                                reg = (reg & 0x20) ? 0x02 : 0x00;
5127                                setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5128                        }
5129                }
5130
5131                v1 = bios[0x77];
5132
5133                inSISIDXREG(SISSR, 0x3b, reg);
5134                if(reg & 0x02) {
5135                        inSISIDXREG(SISSR, 0x3a, reg);
5136                        v2 = (reg & 0x30) >> 3;
5137                        if(!(v2 & 0x04)) v2 ^= 0x02;
5138                        inSISIDXREG(SISSR, 0x39, reg);
5139                        if(reg & 0x80) v2 |= 0x80;
5140                        v2 |= 0x01;
5141
5142                        if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5143                                pci_dev_put(mypdev);
5144                                if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5145                                        v2 &= 0xf9;
5146                                v2 |= 0x08;
5147                                v1 &= 0xfe;
5148                        } else {
5149                                mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
5150                                if(!mypdev)
5151                                        mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
5152                                if(!mypdev)
5153                                        mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
5154                                if(mypdev) {
5155                                        pci_read_config_dword(mypdev, 0x94, &regd);
5156                                        regd &= 0xfffffeff;
5157                                        pci_write_config_dword(mypdev, 0x94, regd);
5158                                        v1 &= 0xfe;
5159                                        pci_dev_put(mypdev);
5160                                } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5161                                        v1 &= 0xfe;
5162                                } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5163                                          sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5164                                          sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5165                                          sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5166                                        if((v2 & 0x06) == 4)
5167                                                v2 ^= 0x06;
5168                                        v2 |= 0x08;
5169                                }
5170                        }
5171                        setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5172                }
5173                outSISIDXREG(SISSR, 0x22, v1);
5174
5175                if(ivideo->revision_id == 2) {
5176                        inSISIDXREG(SISSR, 0x3b, v1);
5177                        inSISIDXREG(SISSR, 0x3a, v2);
5178                        regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5179                        if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5180                                setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5181
5182                        if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
5183                                /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5184                                 * of nforce 2 ROM
5185                                 */
5186                                if(0)
5187                                        setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5188                                pci_dev_put(mypdev);
5189                        }
5190                }
5191
5192                v1 = 0x30;
5193                inSISIDXREG(SISSR, 0x3b, reg);
5194                inSISIDXREG(SISCR, 0x5f, v2);
5195                if((!(reg & 0x02)) && (v2 & 0x0e))
5196                        v1 |= 0x08;
5197                outSISIDXREG(SISSR, 0x27, v1);
5198
5199                if(bios[0x64] & 0x01) {
5200                        setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5201                }
5202
5203                v1 = bios[0x4f7];
5204                pci_read_config_dword(pdev, 0x50, &regd);
5205                regd = (regd >> 20) & 0x0f;
5206                if(regd == 1) {
5207                        v1 &= 0xfc;
5208                        orSISIDXREG(SISCR, 0x5f, 0x08);
5209                }
5210                outSISIDXREG(SISCR, 0x48, v1);
5211
5212                setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5213                setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5214                setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5215                setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5216                setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5217                outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5218                setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5219                outSISIDXREG(SISCR, 0x74, 0xd0);
5220                setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5221                setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5222                setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5223                v1 = bios[0x501];
5224                if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
5225                        v1 = 0xf0;
5226                        pci_dev_put(mypdev);
5227                }
5228                outSISIDXREG(SISCR, 0x77, v1);
5229        }
5230
5231        /* RAM type */
5232
5233        regb = 0;       /* ! */
5234
5235        v1 = 0xff;
5236        if(ivideo->haveXGIROM) {
5237                v1 = bios[0x140 + regb];
5238        }
5239        outSISIDXREG(SISCR, 0x6d, v1);
5240
5241        ptr = cs128;
5242        if(ivideo->haveXGIROM) {
5243                ptr = (const u8 *)&bios[0x128];
5244        }
5245        for(i = 0, j = 0; i < 3; i++, j += 8) {
5246                outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5247        }
5248
5249        ptr  = cs31a;
5250        ptr2 = cs33a;
5251        if(ivideo->haveXGIROM) {
5252                index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5253                ptr  = (const u8 *)&bios[index];
5254                ptr2 = (const u8 *)&bios[index + 0x20];
5255        }
5256        for(i = 0; i < 2; i++) {
5257                if(i == 0) {
5258                        regd = le32_to_cpu(((u32 *)ptr)[regb]);
5259                        rega = 0x6b;
5260                } else {
5261                        regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5262                        rega = 0x6e;
5263                }
5264                reg = 0x00;
5265                for(j = 0; j < 16; j++) {
5266                        reg &= 0xf3;
5267                        if(regd & 0x01) reg |= 0x04;
5268                        if(regd & 0x02) reg |= 0x08;
5269                        regd >>= 2;
5270                        outSISIDXREG(SISCR, rega, reg);
5271                        inSISIDXREG(SISCR, rega, reg);
5272                        inSISIDXREG(SISCR, rega, reg);
5273                        reg += 0x10;
5274                }
5275        }
5276
5277        andSISIDXREG(SISCR, 0x6e, 0xfc);
5278
5279        ptr  = NULL;
5280        if(ivideo->haveXGIROM) {
5281                index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5282                ptr  = (const u8 *)&bios[index];
5283        }
5284        for(i = 0; i < 4; i++) {
5285                setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5286                reg = 0x00;
5287                for(j = 0; j < 2; j++) {
5288                        regd = 0;
5289                        if(ptr) {
5290                                regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5291                                ptr += 4;
5292                        }
5293                        /* reg = 0x00; */
5294                        for(k = 0; k < 16; k++) {
5295                                reg &= 0xfc;
5296                                if(regd & 0x01) reg |= 0x01;
5297                                if(regd & 0x02) reg |= 0x02;
5298                                regd >>= 2;
5299                                outSISIDXREG(SISCR, 0x6f, reg);
5300                                inSISIDXREG(SISCR, 0x6f, reg);
5301                                inSISIDXREG(SISCR, 0x6f, reg);
5302                                reg += 0x08;
5303                        }
5304                }
5305        }
5306
5307        ptr  = cs148;
5308        if(ivideo->haveXGIROM) {
5309                ptr  = (const u8 *)&bios[0x148];
5310        }
5311        for(i = 0, j = 0; i < 2; i++, j += 8) {
5312                outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5313        }
5314
5315        andSISIDXREG(SISCR, 0x89, 0x8f);
5316
5317        ptr  = cs45a;
5318        if(ivideo->haveXGIROM) {
5319                index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5320                ptr  = (const u8 *)&bios[index];
5321        }
5322        regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5323        reg = 0x80;
5324        for(i = 0; i < 5; i++) {
5325                reg &= 0xfc;
5326                if(regd & 0x01) reg |= 0x01;
5327                if(regd & 0x02) reg |= 0x02;
5328                regd >>= 2;
5329                outSISIDXREG(SISCR, 0x89, reg);
5330                inSISIDXREG(SISCR, 0x89, reg);
5331                inSISIDXREG(SISCR, 0x89, reg);
5332                reg += 0x10;
5333        }
5334
5335        v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5336        if(ivideo->haveXGIROM) {
5337                v1 = bios[0x118 + regb];
5338                v2 = bios[0xf8 + regb];
5339                v3 = bios[0x120 + regb];
5340                v4 = bios[0x1ca];
5341        }
5342        outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5343        outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5344        orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5345        outSISIDXREG(SISCR, 0x41, v2);
5346
5347        ptr  = cs170;
5348        if(ivideo->haveXGIROM) {
5349                ptr  = (const u8 *)&bios[0x170];
5350        }
5351        for(i = 0, j = 0; i < 7; i++, j += 8) {
5352                outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5353        }
5354
5355        outSISIDXREG(SISCR, 0x59, v3);
5356
5357        ptr  = cs1a8;
5358        if(ivideo->haveXGIROM) {
5359                ptr  = (const u8 *)&bios[0x1a8];
5360        }
5361        for(i = 0, j = 0; i < 3; i++, j += 8) {
5362                outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5363        }
5364
5365        ptr  = cs100;
5366        if(ivideo->haveXGIROM) {
5367                ptr  = (const u8 *)&bios[0x100];
5368        }
5369        for(i = 0, j = 0; i < 2; i++, j += 8) {
5370                outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5371        }
5372
5373        outSISIDXREG(SISCR, 0xcf, v4);
5374
5375        outSISIDXREG(SISCR, 0x83, 0x09);
5376        outSISIDXREG(SISCR, 0x87, 0x00);
5377
5378        if(ivideo->chip == XGI_40) {
5379                if( (ivideo->revision_id == 1) ||
5380                    (ivideo->revision_id == 2) ) {
5381                        outSISIDXREG(SISCR, 0x8c, 0x87);
5382                }
5383        }
5384
5385        outSISIDXREG(SISSR, 0x17, 0x00);
5386        outSISIDXREG(SISSR, 0x1a, 0x87);
5387
5388        if(ivideo->chip == XGI_20) {
5389                outSISIDXREG(SISSR, 0x15, 0x00);
5390                outSISIDXREG(SISSR, 0x1c, 0x00);
5391        }
5392
5393        ramtype = 0x00; v1 = 0x10;
5394        if(ivideo->haveXGIROM) {
5395                ramtype = bios[0x62];
5396                v1 = bios[0x1d2];
5397        }
5398        if(!(ramtype & 0x80)) {
5399                if(ivideo->chip == XGI_20) {
5400                        outSISIDXREG(SISCR, 0x97, v1);
5401                        inSISIDXREG(SISCR, 0x97, reg);
5402                        if(reg & 0x10) {
5403                                ramtype = (reg & 0x01) << 1;
5404                        }
5405                } else {
5406                        inSISIDXREG(SISSR, 0x39, reg);
5407                        ramtype = reg & 0x02;
5408                        if(!(ramtype)) {
5409                                inSISIDXREG(SISSR, 0x3a, reg);
5410                                ramtype = (reg >> 1) & 0x01;
5411                        }
5412                }
5413        }
5414        ramtype &= 0x07;
5415
5416        regb = 0;       /* ! */
5417
5418        switch(ramtype) {
5419        case 0:
5420                sisfb_post_xgi_setclocks(ivideo, regb);
5421                if((ivideo->chip == XGI_20) ||
5422                   (ivideo->revision_id == 1)   ||
5423                   (ivideo->revision_id == 2)) {
5424                        v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5425                        if(ivideo->haveXGIROM) {
5426                                v1 = bios[regb + 0x158];
5427                                v2 = bios[regb + 0x160];
5428                                v3 = bios[regb + 0x168];
5429                        }
5430                        outSISIDXREG(SISCR, 0x82, v1);
5431                        outSISIDXREG(SISCR, 0x85, v2);
5432                        outSISIDXREG(SISCR, 0x86, v3);
5433                } else {
5434                        outSISIDXREG(SISCR, 0x82, 0x88);
5435                        outSISIDXREG(SISCR, 0x86, 0x00);
5436                        inSISIDXREG(SISCR, 0x86, reg);
5437                        outSISIDXREG(SISCR, 0x86, 0x88);
5438                        inSISIDXREG(SISCR, 0x86, reg);
5439                        outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5440                        outSISIDXREG(SISCR, 0x82, 0x77);
5441                        outSISIDXREG(SISCR, 0x85, 0x00);
5442                        inSISIDXREG(SISCR, 0x85, reg);
5443                        outSISIDXREG(SISCR, 0x85, 0x88);
5444                        inSISIDXREG(SISCR, 0x85, reg);
5445                        outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5446                        outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5447                }
5448                if(ivideo->chip == XGI_40) {
5449                        outSISIDXREG(SISCR, 0x97, 0x00);
5450                }
5451                outSISIDXREG(SISCR, 0x98, 0x01);
5452                outSISIDXREG(SISCR, 0x9a, 0x02);
5453
5454                outSISIDXREG(SISSR, 0x18, 0x01);
5455                if((ivideo->chip == XGI_20) ||
5456                   (ivideo->revision_id == 2)) {
5457                        outSISIDXREG(SISSR, 0x19, 0x40);
5458                } else {
5459                        outSISIDXREG(SISSR, 0x19, 0x20);
5460                }
5461                outSISIDXREG(SISSR, 0x16, 0x00);
5462                outSISIDXREG(SISSR, 0x16, 0x80);
5463                if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5464                        sisfb_post_xgi_delay(ivideo, 0x43);
5465                        sisfb_post_xgi_delay(ivideo, 0x43);
5466                        sisfb_post_xgi_delay(ivideo, 0x43);
5467                        outSISIDXREG(SISSR, 0x18, 0x00);
5468                        if((ivideo->chip == XGI_20) ||
5469                           (ivideo->revision_id == 2)) {
5470                                outSISIDXREG(SISSR, 0x19, 0x40);
5471                        } else {
5472                                outSISIDXREG(SISSR, 0x19, 0x20);
5473                        }
5474                } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5475                        /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5476                }
5477                outSISIDXREG(SISSR, 0x16, 0x00);
5478                outSISIDXREG(SISSR, 0x16, 0x80);
5479                sisfb_post_xgi_delay(ivideo, 4);
5480                v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5481                if(ivideo->haveXGIROM) {
5482                        v1 = bios[0xf0];
5483                        index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5484                        v2 = bios[index];
5485                        v3 = bios[index + 1];
5486                        v4 = bios[index + 2];
5487                        v5 = bios[index + 3];
5488                }
5489                outSISIDXREG(SISSR, 0x18, v1);
5490                outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5491                outSISIDXREG(SISSR, 0x16, v2);
5492                outSISIDXREG(SISSR, 0x16, v3);
5493                sisfb_post_xgi_delay(ivideo, 0x43);
5494                outSISIDXREG(SISSR, 0x1b, 0x03);
5495                sisfb_post_xgi_delay(ivideo, 0x22);
5496                outSISIDXREG(SISSR, 0x18, v1);
5497                outSISIDXREG(SISSR, 0x19, 0x00);
5498                outSISIDXREG(SISSR, 0x16, v4);
5499                outSISIDXREG(SISSR, 0x16, v5);
5500                outSISIDXREG(SISSR, 0x1b, 0x00);
5501                break;
5502        case 1:
5503                outSISIDXREG(SISCR, 0x82, 0x77);
5504                outSISIDXREG(SISCR, 0x86, 0x00);
5505                inSISIDXREG(SISCR, 0x86, reg);
5506                outSISIDXREG(SISCR, 0x86, 0x88);
5507                inSISIDXREG(SISCR, 0x86, reg);
5508                v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5509                if(ivideo->haveXGIROM) {
5510                        v1 = bios[regb + 0x168];
5511                        v2 = bios[regb + 0x160];
5512                        v3 = bios[regb + 0x158];
5513                }
5514                outSISIDXREG(SISCR, 0x86, v1);
5515                outSISIDXREG(SISCR, 0x82, 0x77);
5516                outSISIDXREG(SISCR, 0x85, 0x00);
5517                inSISIDXREG(SISCR, 0x85, reg);
5518                outSISIDXREG(SISCR, 0x85, 0x88);
5519                inSISIDXREG(SISCR, 0x85, reg);
5520                outSISIDXREG(SISCR, 0x85, v2);
5521                outSISIDXREG(SISCR, 0x82, v3);
5522                outSISIDXREG(SISCR, 0x98, 0x01);
5523                outSISIDXREG(SISCR, 0x9a, 0x02);
5524
5525                outSISIDXREG(SISSR, 0x28, 0x64);
5526                outSISIDXREG(SISSR, 0x29, 0x63);
5527                sisfb_post_xgi_delay(ivideo, 15);
5528                outSISIDXREG(SISSR, 0x18, 0x00);
5529                outSISIDXREG(SISSR, 0x19, 0x20);
5530                outSISIDXREG(SISSR, 0x16, 0x00);
5531                outSISIDXREG(SISSR, 0x16, 0x80);
5532                outSISIDXREG(SISSR, 0x18, 0xc5);
5533                outSISIDXREG(SISSR, 0x19, 0x23);
5534                outSISIDXREG(SISSR, 0x16, 0x00);
5535                outSISIDXREG(SISSR, 0x16, 0x80);
5536                sisfb_post_xgi_delay(ivideo, 1);
5537                outSISIDXREG(SISCR, 0x97,0x11);
5538                sisfb_post_xgi_setclocks(ivideo, regb);
5539                sisfb_post_xgi_delay(ivideo, 0x46);
5540                outSISIDXREG(SISSR, 0x18, 0xc5);
5541                outSISIDXREG(SISSR, 0x19, 0x23);
5542                outSISIDXREG(SISSR, 0x16, 0x00);
5543                outSISIDXREG(SISSR, 0x16, 0x80);
5544                sisfb_post_xgi_delay(ivideo, 1);
5545                outSISIDXREG(SISSR, 0x1b, 0x04);
5546                sisfb_post_xgi_delay(ivideo, 1);
5547                outSISIDXREG(SISSR, 0x1b, 0x00);
5548                sisfb_post_xgi_delay(ivideo, 1);
5549                v1 = 0x31;
5550                if(ivideo->haveXGIROM) {
5551                        v1 = bios[0xf0];
5552                }
5553                outSISIDXREG(SISSR, 0x18, v1);
5554                outSISIDXREG(SISSR, 0x19, 0x06);
5555                outSISIDXREG(SISSR, 0x16, 0x04);
5556                outSISIDXREG(SISSR, 0x16, 0x84);
5557                sisfb_post_xgi_delay(ivideo, 1);
5558                break;
5559        default:
5560                sisfb_post_xgi_setclocks(ivideo, regb);
5561                if((ivideo->chip == XGI_40) &&
5562                   ((ivideo->revision_id == 1) ||
5563                    (ivideo->revision_id == 2))) {
5564                        outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5565                        outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5566                        outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5567                } else {
5568                        outSISIDXREG(SISCR, 0x82, 0x88);
5569                        outSISIDXREG(SISCR, 0x86, 0x00);
5570                        inSISIDXREG(SISCR, 0x86, reg);
5571                        outSISIDXREG(SISCR, 0x86, 0x88);
5572                        outSISIDXREG(SISCR, 0x82, 0x77);
5573                        outSISIDXREG(SISCR, 0x85, 0x00);
5574                        inSISIDXREG(SISCR, 0x85, reg);
5575                        outSISIDXREG(SISCR, 0x85, 0x88);
5576                        inSISIDXREG(SISCR, 0x85, reg);
5577                        v1 = cs160[regb]; v2 = cs158[regb];
5578                        if(ivideo->haveXGIROM) {
5579                                v1 = bios[regb + 0x160];
5580                                v2 = bios[regb + 0x158];
5581                        }
5582                        outSISIDXREG(SISCR, 0x85, v1);
5583                        outSISIDXREG(SISCR, 0x82, v2);
5584                }
5585                if(ivideo->chip == XGI_40) {
5586                        outSISIDXREG(SISCR, 0x97, 0x11);
5587                }
5588                if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5589                        outSISIDXREG(SISCR, 0x98, 0x01);
5590                } else {
5591                        outSISIDXREG(SISCR, 0x98, 0x03);
5592                }
5593                outSISIDXREG(SISCR, 0x9a, 0x02);
5594
5595                if(ivideo->chip == XGI_40) {
5596                        outSISIDXREG(SISSR, 0x18, 0x01);
5597                } else {
5598                        outSISIDXREG(SISSR, 0x18, 0x00);
5599                }
5600                outSISIDXREG(SISSR, 0x19, 0x40);
5601                outSISIDXREG(SISSR, 0x16, 0x00);
5602                outSISIDXREG(SISSR, 0x16, 0x80);
5603                if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5604                        sisfb_post_xgi_delay(ivideo, 0x43);
5605                        sisfb_post_xgi_delay(ivideo, 0x43);
5606                        sisfb_post_xgi_delay(ivideo, 0x43);
5607                        outSISIDXREG(SISSR, 0x18, 0x00);
5608                        outSISIDXREG(SISSR, 0x19, 0x40);
5609                        outSISIDXREG(SISSR, 0x16, 0x00);
5610                        outSISIDXREG(SISSR, 0x16, 0x80);
5611                }
5612                sisfb_post_xgi_delay(ivideo, 4);
5613                v1 = 0x31;
5614                if(ivideo->haveXGIROM) {
5615                        v1 = bios[0xf0];
5616                }
5617                outSISIDXREG(SISSR, 0x18, v1);
5618                outSISIDXREG(SISSR, 0x19, 0x01);
5619                if(ivideo->chip == XGI_40) {
5620                        outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5621                        outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5622                } else {
5623                        outSISIDXREG(SISSR, 0x16, 0x05);
5624                        outSISIDXREG(SISSR, 0x16, 0x85);
5625                }
5626                sisfb_post_xgi_delay(ivideo, 0x43);
5627                if(ivideo->chip == XGI_40) {
5628                        outSISIDXREG(SISSR, 0x1b, 0x01);
5629                } else {
5630                        outSISIDXREG(SISSR, 0x1b, 0x03);
5631                }
5632                sisfb_post_xgi_delay(ivideo, 0x22);
5633                outSISIDXREG(SISSR, 0x18, v1);
5634                outSISIDXREG(SISSR, 0x19, 0x00);
5635                if(ivideo->chip == XGI_40) {
5636                        outSISIDXREG(SISSR, 0x16, bios[0x540]);
5637                        outSISIDXREG(SISSR, 0x16, bios[0x541]);
5638                } else {
5639                        outSISIDXREG(SISSR, 0x16, 0x05);
5640                        outSISIDXREG(SISSR, 0x16, 0x85);
5641                }
5642                outSISIDXREG(SISSR, 0x1b, 0x00);
5643        }
5644
5645        regb = 0;       /* ! */
5646        v1 = 0x03;
5647        if(ivideo->haveXGIROM) {
5648                v1 = bios[0x110 + regb];
5649        }
5650        outSISIDXREG(SISSR, 0x1b, v1);
5651
5652        /* RAM size */
5653        v1 = 0x00; v2 = 0x00;
5654        if(ivideo->haveXGIROM) {
5655                v1 = bios[0x62];
5656                v2 = bios[0x63];
5657        }
5658        regb = 0;       /* ! */
5659        regd = 1 << regb;
5660        if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5661
5662                outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5663                outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5664
5665        } else {
5666
5667                /* Set default mode, don't clear screen */
5668                ivideo->SiS_Pr.SiS_UseOEM = false;
5669                SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5670                SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5671                ivideo->curFSTN = ivideo->curDSTN = 0;
5672                ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5673                SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5674
5675                outSISIDXREG(SISSR, 0x05, 0x86);
5676
5677                /* Disable read-cache */
5678                andSISIDXREG(SISSR, 0x21, 0xdf);
5679                sisfb_post_xgi_ramsize(ivideo);
5680                /* Enable read-cache */
5681                orSISIDXREG(SISSR, 0x21, 0x20);
5682
5683        }
5684
5685#if 0
5686        printk(KERN_DEBUG "-----------------\n");
5687        for(i = 0; i < 0xff; i++) {
5688                inSISIDXREG(SISCR, i, reg);
5689                printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5690        }
5691        for(i = 0; i < 0x40; i++) {
5692                inSISIDXREG(SISSR, i, reg);
5693                printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5694        }
5695        printk(KERN_DEBUG "-----------------\n");
5696#endif
5697
5698        /* Sense CRT1 */
5699        if(ivideo->chip == XGI_20) {
5700                orSISIDXREG(SISCR, 0x32, 0x20);
5701        } else {
5702                inSISIDXREG(SISPART4, 0x00, reg);
5703                if((reg == 1) || (reg == 2)) {
5704                        sisfb_sense_crt1(ivideo);
5705                } else {
5706                        orSISIDXREG(SISCR, 0x32, 0x20);
5707                }
5708        }
5709
5710        /* Set default mode, don't clear screen */
5711        ivideo->SiS_Pr.SiS_UseOEM = false;
5712        SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5713        SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5714        ivideo->curFSTN = ivideo->curDSTN = 0;
5715        SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5716
5717        outSISIDXREG(SISSR, 0x05, 0x86);
5718
5719        /* Display off */
5720        orSISIDXREG(SISSR, 0x01, 0x20);
5721
5722        /* Save mode number in CR34 */
5723        outSISIDXREG(SISCR, 0x34, 0x2e);
5724
5725        /* Let everyone know what the current mode is */
5726        ivideo->modeprechange = 0x2e;
5727
5728        if(ivideo->chip == XGI_40) {
5729                inSISIDXREG(SISCR, 0xca, reg);
5730                inSISIDXREG(SISCR, 0xcc, v1);
5731                if((reg & 0x10) && (!(v1 & 0x04))) {
5732                        printk(KERN_ERR
5733                                "sisfb: Please connect power to the card.\n");
5734                        return 0;
5735                }
5736        }
5737
5738        return 1;
5739}
5740#endif
5741
5742static int __devinit
5743sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5744{
5745        struct sisfb_chip_info  *chipinfo = &sisfb_chip_info[ent->driver_data];
5746        struct sis_video_info   *ivideo = NULL;
5747        struct fb_info          *sis_fb_info = NULL;
5748        u16 reg16;
5749        u8  reg;
5750        int i, ret;
5751
5752        if(sisfb_off)
5753                return -ENXIO;
5754
5755        sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5756        if(!sis_fb_info)
5757                return -ENOMEM;
5758
5759        ivideo = (struct sis_video_info *)sis_fb_info->par;
5760        ivideo->memyselfandi = sis_fb_info;
5761
5762        ivideo->sisfb_id = SISFB_ID;
5763
5764        if(card_list == NULL) {
5765                ivideo->cardnumber = 0;
5766        } else {
5767                struct sis_video_info *countvideo = card_list;
5768                ivideo->cardnumber = 1;
5769                while((countvideo = countvideo->next) != NULL)
5770                        ivideo->cardnumber++;
5771        }
5772
5773        strncpy(ivideo->myid, chipinfo->chip_name, 30);
5774
5775        ivideo->warncount = 0;
5776        ivideo->chip_id = pdev->device;
5777        ivideo->chip_vendor = pdev->vendor;
5778        ivideo->revision_id = pdev->revision;
5779        ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5780        pci_read_config_word(pdev, PCI_COMMAND, &reg16);
5781        ivideo->sisvga_enabled = reg16 & 0x01;
5782        ivideo->pcibus = pdev->bus->number;
5783        ivideo->pcislot = PCI_SLOT(pdev->devfn);
5784        ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5785        ivideo->subsysvendor = pdev->subsystem_vendor;
5786        ivideo->subsysdevice = pdev->subsystem_device;
5787
5788#ifndef MODULE
5789        if(sisfb_mode_idx == -1) {
5790                sisfb_get_vga_mode_from_kernel();
5791        }
5792#endif
5793
5794        ivideo->chip = chipinfo->chip;
5795        ivideo->sisvga_engine = chipinfo->vgaengine;
5796        ivideo->hwcursor_size = chipinfo->hwcursor_size;
5797        ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5798        ivideo->mni = chipinfo->mni;
5799
5800        ivideo->detectedpdc  = 0xff;
5801        ivideo->detectedpdca = 0xff;
5802        ivideo->detectedlcda = 0xff;
5803
5804        ivideo->sisfb_thismonitor.datavalid = false;
5805
5806        ivideo->current_base = 0;
5807
5808        ivideo->engineok = 0;
5809
5810        ivideo->sisfb_was_boot_device = 0;
5811
5812        if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5813                if(ivideo->sisvga_enabled)
5814                        ivideo->sisfb_was_boot_device = 1;
5815                else {
5816                        printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5817                                "but marked as boot video device ???\n");
5818                        printk(KERN_DEBUG "sisfb: I will not accept this "
5819                                "as the primary VGA device\n");
5820                }
5821        }
5822
5823        ivideo->sisfb_parm_mem = sisfb_parm_mem;
5824        ivideo->sisfb_accel = sisfb_accel;
5825        ivideo->sisfb_ypan = sisfb_ypan;
5826        ivideo->sisfb_max = sisfb_max;
5827        ivideo->sisfb_userom = sisfb_userom;
5828        ivideo->sisfb_useoem = sisfb_useoem;
5829        ivideo->sisfb_mode_idx = sisfb_mode_idx;
5830        ivideo->sisfb_parm_rate = sisfb_parm_rate;
5831        ivideo->sisfb_crt1off = sisfb_crt1off;
5832        ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5833        ivideo->sisfb_crt2type = sisfb_crt2type;
5834        ivideo->sisfb_crt2flags = sisfb_crt2flags;
5835        /* pdc(a), scalelcd, special timing, lvdshl handled below */
5836        ivideo->sisfb_dstn = sisfb_dstn;
5837        ivideo->sisfb_fstn = sisfb_fstn;
5838        ivideo->sisfb_tvplug = sisfb_tvplug;
5839        ivideo->sisfb_tvstd = sisfb_tvstd;
5840        ivideo->tvxpos = sisfb_tvxposoffset;
5841        ivideo->tvypos = sisfb_tvyposoffset;
5842        ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5843        ivideo->refresh_rate = 0;
5844        if(ivideo->sisfb_parm_rate != -1) {
5845                ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5846        }
5847
5848        ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5849        ivideo->SiS_Pr.CenterScreen = -1;
5850        ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5851        ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5852
5853        ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5854        ivideo->SiS_Pr.SiS_CHOverScan = -1;
5855        ivideo->SiS_Pr.SiS_ChSW = false;
5856        ivideo->SiS_Pr.SiS_UseLCDA = false;
5857        ivideo->SiS_Pr.HaveEMI = false;
5858        ivideo->SiS_Pr.HaveEMILCD = false;
5859        ivideo->SiS_Pr.OverruleEMI = false;
5860        ivideo->SiS_Pr.SiS_SensibleSR11 = false;
5861        ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5862        ivideo->SiS_Pr.PDC  = -1;
5863        ivideo->SiS_Pr.PDCA = -1;
5864        ivideo->SiS_Pr.DDCPortMixup = false;
5865#ifdef CONFIG_FB_SIS_315
5866        if(ivideo->chip >= SIS_330) {
5867                ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5868                if(ivideo->chip >= SIS_661) {
5869                        ivideo->SiS_Pr.SiS_SensibleSR11 = true;
5870                }
5871        }
5872#endif
5873
5874        memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5875
5876        pci_set_drvdata(pdev, ivideo);
5877
5878        /* Patch special cases */
5879        if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5880                switch(ivideo->nbridge->device) {
5881#ifdef CONFIG_FB_SIS_300
5882                case PCI_DEVICE_ID_SI_730:
5883                        ivideo->chip = SIS_730;
5884                        strcpy(ivideo->myid, "SiS 730");
5885                        break;
5886#endif
5887#ifdef CONFIG_FB_SIS_315
5888                case PCI_DEVICE_ID_SI_651:
5889                        /* ivideo->chip is ok */
5890                        strcpy(ivideo->myid, "SiS 651");
5891                        break;
5892                case PCI_DEVICE_ID_SI_740:
5893                        ivideo->chip = SIS_740;
5894                        strcpy(ivideo->myid, "SiS 740");
5895                        break;
5896                case PCI_DEVICE_ID_SI_661:
5897                        ivideo->chip = SIS_661;
5898                        strcpy(ivideo->myid, "SiS 661");
5899                        break;
5900                case PCI_DEVICE_ID_SI_741:
5901                        ivideo->chip = SIS_741;
5902                        strcpy(ivideo->myid, "SiS 741");
5903                        break;
5904                case PCI_DEVICE_ID_SI_760:
5905                        ivideo->chip = SIS_760;
5906                        strcpy(ivideo->myid, "SiS 760");
5907                        break;
5908                case PCI_DEVICE_ID_SI_761:
5909                        ivideo->chip = SIS_761;
5910                        strcpy(ivideo->myid, "SiS 761");
5911                        break;
5912#endif
5913                default:
5914                        break;
5915                }
5916        }
5917
5918        ivideo->SiS_Pr.ChipType = ivideo->chip;
5919
5920        ivideo->SiS_Pr.ivideo = (void *)ivideo;
5921
5922#ifdef CONFIG_FB_SIS_315
5923        if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5924           (ivideo->SiS_Pr.ChipType == SIS_315)) {
5925                ivideo->SiS_Pr.ChipType = SIS_315H;
5926        }
5927#endif
5928
5929        if(!ivideo->sisvga_enabled) {
5930                if(pci_enable_device(pdev)) {
5931                        if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
5932                        pci_set_drvdata(pdev, NULL);
5933                        framebuffer_release(sis_fb_info);
5934                        return -EIO;
5935                }
5936        }
5937
5938        ivideo->video_base = pci_resource_start(pdev, 0);
5939        ivideo->mmio_base  = pci_resource_start(pdev, 1);
5940        ivideo->mmio_size  = pci_resource_len(pdev, 1);
5941        ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
5942        ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
5943
5944        SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
5945
5946#ifdef CONFIG_FB_SIS_300
5947        /* Find PCI systems for Chrontel/GPIO communication setup */
5948        if(ivideo->chip == SIS_630) {
5949                i = 0;
5950                do {
5951                        if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5952                           mychswtable[i].subsysCard   == ivideo->subsysdevice) {
5953                                ivideo->SiS_Pr.SiS_ChSW = true;
5954                                printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5955                                        "requiring Chrontel/GPIO setup\n",
5956                                        mychswtable[i].vendorName,
5957                                        mychswtable[i].cardName);
5958                                ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
5959                                break;
5960                        }
5961                        i++;
5962                } while(mychswtable[i].subsysVendor != 0);
5963        }
5964#endif
5965
5966#ifdef CONFIG_FB_SIS_315
5967        if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
5968                ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
5969        }
5970#endif
5971
5972        outSISIDXREG(SISSR, 0x05, 0x86);
5973
5974        if( (!ivideo->sisvga_enabled)
5975#if !defined(__i386__) && !defined(__x86_64__)
5976                              || (sisfb_resetcard)
5977#endif
5978                                                   ) {
5979                for(i = 0x30; i <= 0x3f; i++) {
5980                        outSISIDXREG(SISCR, i, 0x00);
5981                }
5982        }
5983
5984        /* Find out about current video mode */
5985        ivideo->modeprechange = 0x03;
5986        inSISIDXREG(SISCR, 0x34, reg);
5987        if(reg & 0x7f) {
5988                ivideo->modeprechange = reg & 0x7f;
5989        } else if(ivideo->sisvga_enabled) {
5990#if defined(__i386__) || defined(__x86_64__)
5991                unsigned char __iomem *tt = ioremap(0x400, 0x100);
5992                if(tt) {
5993                        ivideo->modeprechange = readb(tt + 0x49);
5994                        iounmap(tt);
5995                }
5996#endif
5997        }
5998
5999        /* Search and copy ROM image */
6000        ivideo->bios_abase = NULL;
6001        ivideo->SiS_Pr.VirtualRomBase = NULL;
6002        ivideo->SiS_Pr.UseROM = false;
6003        ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
6004        if(ivideo->sisfb_userom) {
6005                ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6006                ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6007                ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
6008                printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6009                        ivideo->SiS_Pr.UseROM ? "" : "not ");
6010                if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6011                   ivideo->SiS_Pr.UseROM = false;
6012                   ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
6013                   if( (ivideo->revision_id == 2) &&
6014                       (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6015                        ivideo->SiS_Pr.DDCPortMixup = true;
6016                   }
6017                }
6018        } else {
6019                printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6020        }
6021
6022        /* Find systems for special custom timing */
6023        if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6024                sisfb_detect_custom_timing(ivideo);
6025        }
6026
6027        /* POST card in case this has not been done by the BIOS */
6028        if( (!ivideo->sisvga_enabled)
6029#if !defined(__i386__) && !defined(__x86_64__)
6030                             || (sisfb_resetcard)
6031#endif
6032                                                 ) {
6033#ifdef CONFIG_FB_SIS_300
6034                if(ivideo->sisvga_engine == SIS_300_VGA) {
6035                        if(ivideo->chip == SIS_300) {
6036                                sisfb_post_sis300(pdev);
6037                                ivideo->sisfb_can_post = 1;
6038                        }
6039                }
6040#endif
6041
6042#ifdef CONFIG_FB_SIS_315
6043                if(ivideo->sisvga_engine == SIS_315_VGA) {
6044                        int result = 1;
6045                /*      if((ivideo->chip == SIS_315H)   ||
6046                           (ivideo->chip == SIS_315)    ||
6047                           (ivideo->chip == SIS_315PRO) ||
6048                           (ivideo->chip == SIS_330)) {
6049                                sisfb_post_sis315330(pdev);
6050                        } else */ if(ivideo->chip == XGI_20) {
6051                                result = sisfb_post_xgi(pdev);
6052                                ivideo->sisfb_can_post = 1;
6053                        } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6054                                result = sisfb_post_xgi(pdev);
6055                                ivideo->sisfb_can_post = 1;
6056                        } else {
6057                                printk(KERN_INFO "sisfb: Card is not "
6058                                        "POSTed and sisfb can't do this either.\n");
6059                        }
6060                        if(!result) {
6061                                printk(KERN_ERR "sisfb: Failed to POST card\n");
6062                                ret = -ENODEV;
6063                                goto error_3;
6064                        }
6065                }
6066#endif
6067        }
6068
6069        ivideo->sisfb_card_posted = 1;
6070
6071        /* Find out about RAM size */
6072        if(sisfb_get_dram_size(ivideo)) {
6073                printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6074                ret = -ENODEV;
6075                goto error_3;
6076        }
6077
6078
6079        /* Enable PCI addressing and MMIO */
6080        if((ivideo->sisfb_mode_idx < 0) ||
6081           ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6082                /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
6083                orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6084                /* Enable 2D accelerator engine */
6085                orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6086        }
6087
6088        if(sisfb_pdc != 0xff) {
6089                if(ivideo->sisvga_engine == SIS_300_VGA)
6090                        sisfb_pdc &= 0x3c;
6091                else
6092                        sisfb_pdc &= 0x1f;
6093                ivideo->SiS_Pr.PDC = sisfb_pdc;
6094        }
6095#ifdef CONFIG_FB_SIS_315
6096        if(ivideo->sisvga_engine == SIS_315_VGA) {
6097                if(sisfb_pdca != 0xff)
6098                        ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6099        }
6100#endif
6101
6102        if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6103                printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6104                                (int)(ivideo->video_size >> 20));
6105                printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6106                ret = -ENODEV;
6107                goto error_3;
6108        }
6109
6110        if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6111                printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6112                ret = -ENODEV;
6113                goto error_2;
6114        }
6115
6116        ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6117        ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6118        if(!ivideo->video_vbase) {
6119                printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6120                ret = -ENODEV;
6121                goto error_1;
6122        }
6123
6124        ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6125        if(!ivideo->mmio_vbase) {
6126                printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6127                ret = -ENODEV;
6128error_0:        iounmap(ivideo->video_vbase);
6129error_1:        release_mem_region(ivideo->video_base, ivideo->video_size);
6130error_2:        release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6131error_3:        vfree(ivideo->bios_abase);
6132                if(ivideo->lpcdev)
6133                        pci_dev_put(ivideo->lpcdev);
6134                if(ivideo->nbridge)
6135                        pci_dev_put(ivideo->nbridge);
6136                pci_set_drvdata(pdev, NULL);
6137                if(!ivideo->sisvga_enabled)
6138                        pci_disable_device(pdev);
6139                framebuffer_release(sis_fb_info);
6140                return ret;
6141        }
6142
6143        printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6144                ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6145
6146        if(ivideo->video_offset) {
6147                printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6148                        ivideo->video_offset / 1024);
6149        }
6150
6151        printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6152                ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6153
6154
6155        /* Determine the size of the command queue */
6156        if(ivideo->sisvga_engine == SIS_300_VGA) {
6157                ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6158        } else {
6159                if(ivideo->chip == XGI_20) {
6160                        ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6161                } else {
6162                        ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6163                }
6164        }
6165
6166        /* Engines are no longer initialized here; this is
6167         * now done after the first mode-switch (if the
6168         * submitted var has its acceleration flags set).
6169         */
6170
6171        /* Calculate the base of the (unused) hw cursor */
6172        ivideo->hwcursor_vbase = ivideo->video_vbase
6173                                 + ivideo->video_size
6174                                 - ivideo->cmdQueueSize
6175                                 - ivideo->hwcursor_size;
6176        ivideo->caps |= HW_CURSOR_CAP;
6177
6178        /* Initialize offscreen memory manager */
6179        if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6180                printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6181        }
6182
6183        /* Used for clearing the screen only, therefore respect our mem limit */
6184        ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6185        ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6186
6187        ivideo->mtrr = -1;
6188
6189        ivideo->vbflags = 0;
6190        ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6191        ivideo->tvdefmodeidx  = DEFAULT_TVMODE;
6192        ivideo->defmodeidx    = DEFAULT_MODE;
6193
6194        ivideo->newrom = 0;
6195        if(ivideo->chip < XGI_20) {
6196                if(ivideo->bios_abase) {
6197                        ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6198                }
6199        }
6200
6201        if((ivideo->sisfb_mode_idx < 0) ||
6202           ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6203
6204                sisfb_sense_crt1(ivideo);
6205
6206                sisfb_get_VB_type(ivideo);
6207
6208                if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6209                        sisfb_detect_VB_connect(ivideo);
6210                }
6211
6212                ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6213
6214                /* Decide on which CRT2 device to use */
6215                if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6216                        if(ivideo->sisfb_crt2type != -1) {
6217                                if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6218                                   (ivideo->vbflags & CRT2_LCD)) {
6219                                        ivideo->currentvbflags |= CRT2_LCD;
6220                                } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6221                                        ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6222                                }
6223                        } else {
6224                                /* Chrontel 700x TV detection often unreliable, therefore
6225                                 * use a different default order on such machines
6226                                 */
6227                                if((ivideo->sisvga_engine == SIS_300_VGA) &&
6228                                   (ivideo->vbflags2 & VB2_CHRONTEL)) {
6229                                        if(ivideo->vbflags & CRT2_LCD)
6230                                                ivideo->currentvbflags |= CRT2_LCD;
6231                                        else if(ivideo->vbflags & CRT2_TV)
6232                                                ivideo->currentvbflags |= CRT2_TV;
6233                                        else if(ivideo->vbflags & CRT2_VGA)
6234                                                ivideo->currentvbflags |= CRT2_VGA;
6235                                } else {
6236                                        if(ivideo->vbflags & CRT2_TV)
6237                                                ivideo->currentvbflags |= CRT2_TV;
6238                                        else if(ivideo->vbflags & CRT2_LCD)
6239                                                ivideo->currentvbflags |= CRT2_LCD;
6240                                        else if(ivideo->vbflags & CRT2_VGA)
6241                                                ivideo->currentvbflags |= CRT2_VGA;
6242                                }
6243                        }
6244                }
6245
6246                if(ivideo->vbflags & CRT2_LCD) {
6247                        sisfb_detect_lcd_type(ivideo);
6248                }
6249
6250                sisfb_save_pdc_emi(ivideo);
6251
6252                if(!ivideo->sisfb_crt1off) {
6253                        sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6254                } else {
6255                        if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6256                           (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6257                                sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6258                        }
6259                }
6260
6261                if(ivideo->sisfb_mode_idx >= 0) {
6262                        int bu = ivideo->sisfb_mode_idx;
6263                        ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6264                                        ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6265                        if(bu != ivideo->sisfb_mode_idx) {
6266                                printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6267                                        sisbios_mode[bu].xres,
6268                                        sisbios_mode[bu].yres,
6269                                        sisbios_mode[bu].bpp);
6270                        }
6271                }
6272
6273                if(ivideo->sisfb_mode_idx < 0) {
6274                        switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6275                           case CRT2_LCD:
6276                                ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6277                                break;
6278                           case CRT2_TV:
6279                                ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6280                                break;
6281                           default:
6282                                ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6283                                break;
6284                        }
6285                }
6286
6287                ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6288
6289                if(ivideo->refresh_rate != 0) {
6290                        sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6291                                                ivideo->sisfb_mode_idx);
6292                }
6293
6294                if(ivideo->rate_idx == 0) {
6295                        ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6296                        ivideo->refresh_rate = 60;
6297                }
6298
6299                if(ivideo->sisfb_thismonitor.datavalid) {
6300                        if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6301                                                ivideo->sisfb_mode_idx,
6302                                                ivideo->rate_idx,
6303                                                ivideo->refresh_rate)) {
6304                                printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6305                                                        "exceeds monitor specs!\n");
6306                        }
6307                }
6308
6309                ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6310                ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6311                ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6312
6313                sisfb_set_vparms(ivideo);
6314
6315                printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6316                        ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6317                        ivideo->refresh_rate);
6318
6319                /* Set up the default var according to chosen default display mode */
6320                ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6321                ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6322                ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6323
6324                sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6325
6326                ivideo->default_var.pixclock = (u32) (1000000000 /
6327                        sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6328
6329                if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6330                                                ivideo->rate_idx, &ivideo->default_var)) {
6331                        if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6332                                ivideo->default_var.pixclock <<= 1;
6333                        }
6334                }
6335
6336                if(ivideo->sisfb_ypan) {
6337                        /* Maximize regardless of sisfb_max at startup */
6338                        ivideo->default_var.yres_virtual =
6339                                sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6340                        if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6341                                ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6342                        }
6343                }
6344
6345                sisfb_calc_pitch(ivideo, &ivideo->default_var);
6346
6347                ivideo->accel = 0;
6348                if(ivideo->sisfb_accel) {
6349                        ivideo->accel = -1;
6350#ifdef STUPID_ACCELF_TEXT_SHIT
6351                        ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6352#endif
6353                }
6354                sisfb_initaccel(ivideo);
6355
6356#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6357                sis_fb_info->flags = FBINFO_DEFAULT             |
6358                                     FBINFO_HWACCEL_YPAN        |
6359                                     FBINFO_HWACCEL_XPAN        |
6360                                     FBINFO_HWACCEL_COPYAREA    |
6361                                     FBINFO_HWACCEL_FILLRECT    |
6362                                     ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6363#else
6364                sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6365#endif
6366                sis_fb_info->var = ivideo->default_var;
6367                sis_fb_info->fix = ivideo->sisfb_fix;
6368                sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6369                sis_fb_info->fbops = &sisfb_ops;
6370                sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6371
6372                fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6373
6374                printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6375
6376#ifdef CONFIG_MTRR
6377                ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6378                                        MTRR_TYPE_WRCOMB, 1);
6379                if(ivideo->mtrr < 0) {
6380                        printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6381                }
6382#endif
6383
6384                if(register_framebuffer(sis_fb_info) < 0) {
6385                        printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6386                        ret = -EINVAL;
6387                        iounmap(ivideo->mmio_vbase);
6388                        goto error_0;
6389                }
6390
6391                ivideo->registered = 1;
6392
6393                /* Enlist us */
6394                ivideo->next = card_list;
6395                card_list = ivideo;
6396
6397                printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6398                        ivideo->sisfb_accel ? "enabled" : "disabled",
6399                        ivideo->sisfb_ypan  ?
6400                                (ivideo->sisfb_max ? "enabled (auto-max)" :
6401                                                "enabled (no auto-max)") :
6402                                                                        "disabled");
6403
6404
6405                printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6406                        sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6407
6408                printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6409
6410        }       /* if mode = "none" */
6411
6412        return 0;
6413}
6414
6415/*****************************************************/
6416/*                PCI DEVICE HANDLING                */
6417/*****************************************************/
6418
6419static void __devexit sisfb_remove(struct pci_dev *pdev)
6420{
6421        struct sis_video_info   *ivideo = pci_get_drvdata(pdev);
6422        struct fb_info          *sis_fb_info = ivideo->memyselfandi;
6423        int                     registered = ivideo->registered;
6424        int                     modechanged = ivideo->modechanged;
6425
6426        /* Unmap */
6427        iounmap(ivideo->mmio_vbase);
6428        iounmap(ivideo->video_vbase);
6429
6430        /* Release mem regions */
6431        release_mem_region(ivideo->video_base, ivideo->video_size);
6432        release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6433
6434        vfree(ivideo->bios_abase);
6435
6436        if(ivideo->lpcdev)
6437                pci_dev_put(ivideo->lpcdev);
6438
6439        if(ivideo->nbridge)
6440                pci_dev_put(ivideo->nbridge);
6441
6442#ifdef CONFIG_MTRR
6443        /* Release MTRR region */
6444        if(ivideo->mtrr >= 0)
6445                mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6446#endif
6447
6448        pci_set_drvdata(pdev, NULL);
6449
6450        /* If device was disabled when starting, disable
6451         * it when quitting.
6452         */
6453        if(!ivideo->sisvga_enabled)
6454                pci_disable_device(pdev);
6455
6456        /* Unregister the framebuffer */
6457        if(ivideo->registered) {
6458                unregister_framebuffer(sis_fb_info);
6459                framebuffer_release(sis_fb_info);
6460        }
6461
6462        /* OK, our ivideo is gone for good from here. */
6463
6464        /* TODO: Restore the initial mode
6465         * This sounds easy but is as good as impossible
6466         * on many machines with SiS chip and video bridge
6467         * since text modes are always set up differently
6468         * from machine to machine. Depends on the type
6469         * of integration between chipset and bridge.
6470         */
6471        if(registered && modechanged)
6472                printk(KERN_INFO
6473                        "sisfb: Restoring of text mode not supported yet\n");
6474};
6475
6476static struct pci_driver sisfb_driver = {
6477        .name           = "sisfb",
6478        .id_table       = sisfb_pci_table,
6479        .probe          = sisfb_probe,
6480        .remove         = __devexit_p(sisfb_remove)
6481};
6482
6483static int __init sisfb_init(void)
6484{
6485#ifndef MODULE
6486        char *options = NULL;
6487
6488        if(fb_get_options("sisfb", &options))
6489                return -ENODEV;
6490
6491        sisfb_setup(options);
6492#endif
6493        return pci_register_driver(&sisfb_driver);
6494}
6495
6496#ifndef MODULE
6497module_init(sisfb_init);
6498#endif
6499
6500/*****************************************************/
6501/*                      MODULE                       */
6502/*****************************************************/
6503
6504#ifdef MODULE
6505
6506static char             *mode = NULL;
6507static int              vesa = -1;
6508static unsigned int     rate = 0;
6509static unsigned int     crt1off = 1;
6510static unsigned int     mem = 0;
6511static char             *forcecrt2type = NULL;
6512static int              forcecrt1 = -1;
6513static int              pdc = -1;
6514static int              pdc1 = -1;
6515static int              noaccel = -1;
6516static int              noypan  = -1;
6517static int              nomax = -1;
6518static int              userom = -1;
6519static int              useoem = -1;
6520static char             *tvstandard = NULL;
6521static int              nocrt2rate = 0;
6522static int              scalelcd = -1;
6523static char             *specialtiming = NULL;
6524static int              lvdshl = -1;
6525static int              tvxposoffset = 0, tvyposoffset = 0;
6526#if !defined(__i386__) && !defined(__x86_64__)
6527static int              resetcard = 0;
6528static int              videoram = 0;
6529#endif
6530
6531static int __init sisfb_init_module(void)
6532{
6533        sisfb_setdefaultparms();
6534
6535        if(rate)
6536                sisfb_parm_rate = rate;
6537
6538        if((scalelcd == 0) || (scalelcd == 1))
6539                sisfb_scalelcd = scalelcd ^ 1;
6540
6541        /* Need to check crt2 type first for fstn/dstn */
6542
6543        if(forcecrt2type)
6544                sisfb_search_crt2type(forcecrt2type);
6545
6546        if(tvstandard)
6547                sisfb_search_tvstd(tvstandard);
6548
6549        if(mode)
6550                sisfb_search_mode(mode, false);
6551        else if(vesa != -1)
6552                sisfb_search_vesamode(vesa, false);
6553
6554        sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6555
6556        sisfb_forcecrt1 = forcecrt1;
6557        if(forcecrt1 == 1)
6558                sisfb_crt1off = 0;
6559        else if(forcecrt1 == 0)
6560                sisfb_crt1off = 1;
6561
6562        if(noaccel == 1)
6563                sisfb_accel = 0;
6564        else if(noaccel == 0)
6565                sisfb_accel = 1;
6566
6567        if(noypan == 1)
6568                sisfb_ypan = 0;
6569        else if(noypan == 0)
6570                sisfb_ypan = 1;
6571
6572        if(nomax == 1)
6573                sisfb_max = 0;
6574        else if(nomax == 0)
6575                sisfb_max = 1;
6576
6577        if(mem)
6578                sisfb_parm_mem = mem;
6579
6580        if(userom != -1)
6581                sisfb_userom = userom;
6582
6583        if(useoem != -1)
6584                sisfb_useoem = useoem;
6585
6586        if(pdc != -1)
6587                sisfb_pdc  = (pdc  & 0x7f);
6588
6589        if(pdc1 != -1)
6590                sisfb_pdca = (pdc1 & 0x1f);
6591
6592        sisfb_nocrt2rate = nocrt2rate;
6593
6594        if(specialtiming)
6595                sisfb_search_specialtiming(specialtiming);
6596
6597        if((lvdshl >= 0) && (lvdshl <= 3))
6598                sisfb_lvdshl = lvdshl;
6599
6600        sisfb_tvxposoffset = tvxposoffset;
6601        sisfb_tvyposoffset = tvyposoffset;
6602
6603#if !defined(__i386__) && !defined(__x86_64__)
6604        sisfb_resetcard = (resetcard) ? 1 : 0;
6605        if(videoram)
6606                sisfb_videoram = videoram;
6607#endif
6608
6609        return sisfb_init();
6610}
6611
6612static void __exit sisfb_remove_module(void)
6613{
6614        pci_unregister_driver(&sisfb_driver);
6615        printk(KERN_DEBUG "sisfb: Module unloaded\n");
6616}
6617
6618module_init(sisfb_init_module);
6619module_exit(sisfb_remove_module);
6620
6621MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6622MODULE_LICENSE("GPL");
6623MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6624
6625module_param(mem, int, 0);
6626module_param(noaccel, int, 0);
6627module_param(noypan, int, 0);
6628module_param(nomax, int, 0);
6629module_param(userom, int, 0);
6630module_param(useoem, int, 0);
6631module_param(mode, charp, 0);
6632module_param(vesa, int, 0);
6633module_param(rate, int, 0);
6634module_param(forcecrt1, int, 0);
6635module_param(forcecrt2type, charp, 0);
6636module_param(scalelcd, int, 0);
6637module_param(pdc, int, 0);
6638module_param(pdc1, int, 0);
6639module_param(specialtiming, charp, 0);
6640module_param(lvdshl, int, 0);
6641module_param(tvstandard, charp, 0);
6642module_param(tvxposoffset, int, 0);
6643module_param(tvyposoffset, int, 0);
6644module_param(nocrt2rate, int, 0);
6645#if !defined(__i386__) && !defined(__x86_64__)
6646module_param(resetcard, int, 0);
6647module_param(videoram, int, 0);
6648#endif
6649
6650MODULE_PARM_DESC(mem,
6651        "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6652          "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6653          "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6654          "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6655          "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6656          "The value is to be specified without 'KB'.\n");
6657
6658MODULE_PARM_DESC(noaccel,
6659        "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6660          "(default: 0)\n");
6661
6662MODULE_PARM_DESC(noypan,
6663        "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6664          "will be performed by redrawing the screen. (default: 0)\n");
6665
6666MODULE_PARM_DESC(nomax,
6667        "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
6668          "memory for the virtual screen in order to optimize scrolling performance. If\n"
6669          "this is set to anything other than 0, sisfb will not do this and thereby \n"
6670          "enable the user to positively specify a virtual Y size of the screen using\n"
6671          "fbset. (default: 0)\n");
6672
6673MODULE_PARM_DESC(mode,
6674        "\nSelects the desired default display mode in the format XxYxDepth,\n"
6675         "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
6676         "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6677         "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6678
6679MODULE_PARM_DESC(vesa,
6680        "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6681         "0x117 (default: 0x0103)\n");
6682
6683MODULE_PARM_DESC(rate,
6684        "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6685          "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6686          "will be ignored (default: 60)\n");
6687
6688MODULE_PARM_DESC(forcecrt1,
6689        "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6690          "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6691          "0=CRT1 OFF) (default: [autodetected])\n");
6692
6693MODULE_PARM_DESC(forcecrt2type,
6694        "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6695          "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6696          "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6697          "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6698          "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6699          "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6700          "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6701          "depends on the very hardware in use. (default: [autodetected])\n");
6702
6703MODULE_PARM_DESC(scalelcd,
6704        "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6705          "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6706          "show black bars around the image, TMDS panels will probably do the scaling\n"
6707          "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6708
6709MODULE_PARM_DESC(pdc,
6710        "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
6711          "should detect this correctly in most cases; however, sometimes this is not\n"
6712          "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
6713          "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6714          "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6715          "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
6716
6717#ifdef CONFIG_FB_SIS_315
6718MODULE_PARM_DESC(pdc1,
6719        "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
6720          "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6721          "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6722          "implemented yet.\n");
6723#endif
6724
6725MODULE_PARM_DESC(specialtiming,
6726        "\nPlease refer to documentation for more information on this option.\n");
6727
6728MODULE_PARM_DESC(lvdshl,
6729        "\nPlease refer to documentation for more information on this option.\n");
6730
6731MODULE_PARM_DESC(tvstandard,
6732        "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6733          "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6734
6735MODULE_PARM_DESC(tvxposoffset,
6736        "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6737          "Default: 0\n");
6738
6739MODULE_PARM_DESC(tvyposoffset,
6740        "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6741          "Default: 0\n");
6742
6743MODULE_PARM_DESC(nocrt2rate,
6744        "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6745          "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6746
6747#if !defined(__i386__) && !defined(__x86_64__)
6748#ifdef CONFIG_FB_SIS_300
6749MODULE_PARM_DESC(resetcard,
6750        "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
6751          "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6752          "currently). Default: 0\n");
6753
6754MODULE_PARM_DESC(videoram,
6755        "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6756          "some non-x86 architectures where the memory auto detection fails. Only\n"
6757          "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
6758#endif
6759#endif
6760
6761#endif     /*  /MODULE  */
6762
6763/* _GPL only for new symbols. */
6764EXPORT_SYMBOL(sis_malloc);
6765EXPORT_SYMBOL(sis_free);
6766EXPORT_SYMBOL_GPL(sis_malloc_new);
6767EXPORT_SYMBOL_GPL(sis_free_new);
6768
6769
6770
6771