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