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