linux/drivers/video/fbdev/sis/sis_main.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * SiS 300/540/630[S]/730[S],
   4 * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX],
   5 * XGI V3XT/V5/V8, Z7
   6 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
   7 *
   8 * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
   9 *
  10 * Author:      Thomas Winischhofer <thomas@winischhofer.net>
  11 *
  12 * Author of (practically wiped) code base:
  13 *              SiS (www.sis.com)
  14 *              Copyright (C) 1999 Silicon Integrated Systems, Inc.
  15 *
  16 * See http://www.winischhofer.net/ for more information and updates
  17 *
  18 * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
  19 * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
  20 */
  21
  22#include <linux/module.h>
  23#include <linux/moduleparam.h>
  24#include <linux/kernel.h>
  25#include <linux/spinlock.h>
  26#include <linux/errno.h>
  27#include <linux/string.h>
  28#include <linux/mm.h>
  29#include <linux/screen_info.h>
  30#include <linux/slab.h>
  31#include <linux/fb.h>
  32#include <linux/selection.h>
  33#include <linux/ioport.h>
  34#include <linux/init.h>
  35#include <linux/pci.h>
  36#include <linux/vmalloc.h>
  37#include <linux/capability.h>
  38#include <linux/fs.h>
  39#include <linux/types.h>
  40#include <linux/uaccess.h>
  41#include <asm/io.h>
  42
  43#include "sis.h"
  44#include "sis_main.h"
  45#include "init301.h"
  46
  47#if !defined(CONFIG_FB_SIS_300) && !defined(CONFIG_FB_SIS_315)
  48#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
  49#warning sisfb will not work!
  50#endif
  51
  52/* ---------------------- Prototypes ------------------------- */
  53
  54/* Interface used by the world */
  55#ifndef MODULE
  56static int sisfb_setup(char *options);
  57#endif
  58
  59/* Interface to the low level console driver */
  60static int sisfb_init(void);
  61
  62/* fbdev routines */
  63static int      sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
  64                                struct fb_info *info);
  65
  66static int      sisfb_ioctl(struct fb_info *info, unsigned int cmd,
  67                            unsigned long arg);
  68static int      sisfb_set_par(struct fb_info *info);
  69static int      sisfb_blank(int blank,
  70                                struct fb_info *info);
  71
  72static void sisfb_handle_command(struct sis_video_info *ivideo,
  73                                 struct sisfb_cmd *sisfb_command);
  74
  75static void     sisfb_search_mode(char *name, bool quiet);
  76static int      sisfb_validate_mode(struct sis_video_info *ivideo, int modeindex, u32 vbflags);
  77static u8       sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate,
  78                                int index);
  79static int      sisfb_setcolreg(unsigned regno, unsigned red, unsigned green,
  80                                unsigned blue, unsigned transp,
  81                                struct fb_info *fb_info);
  82static int      sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
  83                                struct fb_info *info);
  84static void     sisfb_pre_setmode(struct sis_video_info *ivideo);
  85static void     sisfb_post_setmode(struct sis_video_info *ivideo);
  86static bool     sisfb_CheckVBRetrace(struct sis_video_info *ivideo);
  87static bool     sisfbcheckvretracecrt2(struct sis_video_info *ivideo);
  88static bool     sisfbcheckvretracecrt1(struct sis_video_info *ivideo);
  89static bool     sisfb_bridgeisslave(struct sis_video_info *ivideo);
  90static void     sisfb_detect_VB_connect(struct sis_video_info *ivideo);
  91static void     sisfb_get_VB_type(struct sis_video_info *ivideo);
  92static void     sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val);
  93static void     sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val);
  94
  95/* Internal heap routines */
  96static int              sisfb_heap_init(struct sis_video_info *ivideo);
  97static struct SIS_OH *  sisfb_poh_new_node(struct SIS_HEAP *memheap);
  98static struct SIS_OH *  sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size);
  99static void             sisfb_delete_node(struct SIS_OH *poh);
 100static void             sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh);
 101static struct SIS_OH *  sisfb_poh_free(struct SIS_HEAP *memheap, u32 base);
 102static void             sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh);
 103
 104
 105/* ------------------ Internal helper routines ----------------- */
 106
 107static void __init
 108sisfb_setdefaultparms(void)
 109{
 110        sisfb_off               = 0;
 111        sisfb_parm_mem          = 0;
 112        sisfb_accel             = -1;
 113        sisfb_ypan              = -1;
 114        sisfb_max               = -1;
 115        sisfb_userom            = -1;
 116        sisfb_useoem            = -1;
 117        sisfb_mode_idx          = -1;
 118        sisfb_parm_rate         = -1;
 119        sisfb_crt1off           = 0;
 120        sisfb_forcecrt1         = -1;
 121        sisfb_crt2type          = -1;
 122        sisfb_crt2flags         = 0;
 123        sisfb_pdc               = 0xff;
 124        sisfb_pdca              = 0xff;
 125        sisfb_scalelcd          = -1;
 126        sisfb_specialtiming     = CUT_NONE;
 127        sisfb_lvdshl            = -1;
 128        sisfb_dstn              = 0;
 129        sisfb_fstn              = 0;
 130        sisfb_tvplug            = -1;
 131        sisfb_tvstd             = -1;
 132        sisfb_tvxposoffset      = 0;
 133        sisfb_tvyposoffset      = 0;
 134        sisfb_nocrt2rate        = 0;
 135#if !defined(__i386__) && !defined(__x86_64__)
 136        sisfb_resetcard         = 0;
 137        sisfb_videoram          = 0;
 138#endif
 139}
 140
 141/* ------------- Parameter parsing -------------- */
 142
 143static void sisfb_search_vesamode(unsigned int vesamode, bool quiet)
 144{
 145        int i = 0, j = 0;
 146
 147        /* We don't know the hardware specs yet and there is no ivideo */
 148
 149        if(vesamode == 0) {
 150                if(!quiet)
 151                        printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
 152
 153                sisfb_mode_idx = DEFAULT_MODE;
 154
 155                return;
 156        }
 157
 158        vesamode &= 0x1dff;  /* Clean VESA mode number from other flags */
 159
 160        while(sisbios_mode[i++].mode_no[0] != 0) {
 161                if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
 162                    (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
 163                        if(sisfb_fstn) {
 164                                if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
 165                                   sisbios_mode[i-1].mode_no[1] == 0x56 ||
 166                                   sisbios_mode[i-1].mode_no[1] == 0x53)
 167                                        continue;
 168                        } else {
 169                                if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
 170                                   sisbios_mode[i-1].mode_no[1] == 0x5b)
 171                                        continue;
 172                        }
 173                        sisfb_mode_idx = i - 1;
 174                        j = 1;
 175                        break;
 176                }
 177        }
 178        if((!j) && !quiet)
 179                printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
 180}
 181
 182static void sisfb_search_mode(char *name, bool quiet)
 183{
 184        unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
 185        int i = 0;
 186        char strbuf[16], strbuf1[20];
 187        char *nameptr = name;
 188
 189        /* We don't know the hardware specs yet and there is no ivideo */
 190
 191        if(name == NULL) {
 192                if(!quiet)
 193                        printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
 194
 195                sisfb_mode_idx = DEFAULT_MODE;
 196                return;
 197        }
 198
 199        if(!strncasecmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
 200                if(!quiet)
 201                        printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
 202
 203                sisfb_mode_idx = DEFAULT_MODE;
 204                return;
 205        }
 206
 207        if(strlen(name) <= 19) {
 208                strcpy(strbuf1, name);
 209                for(i = 0; i < strlen(strbuf1); i++) {
 210                        if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
 211                }
 212
 213                /* This does some fuzzy mode naming detection */
 214                if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
 215                        if((rate <= 32) || (depth > 32)) {
 216                                j = rate; rate = depth; depth = j;
 217                        }
 218                        sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
 219                        nameptr = strbuf;
 220                        sisfb_parm_rate = rate;
 221                } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
 222                        sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
 223                        nameptr = strbuf;
 224                } else {
 225                        xres = 0;
 226                        if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
 227                                sprintf(strbuf, "%ux%ux8", xres, yres);
 228                                nameptr = strbuf;
 229                        } else {
 230                                sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
 231                                return;
 232                        }
 233                }
 234        }
 235
 236        i = 0; j = 0;
 237        while(sisbios_mode[i].mode_no[0] != 0) {
 238                if(!strncasecmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
 239                        if(sisfb_fstn) {
 240                                if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
 241                                   sisbios_mode[i-1].mode_no[1] == 0x56 ||
 242                                   sisbios_mode[i-1].mode_no[1] == 0x53)
 243                                        continue;
 244                        } else {
 245                                if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
 246                                   sisbios_mode[i-1].mode_no[1] == 0x5b)
 247                                        continue;
 248                        }
 249                        sisfb_mode_idx = i - 1;
 250                        j = 1;
 251                        break;
 252                }
 253        }
 254
 255        if((!j) && !quiet)
 256                printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
 257}
 258
 259#ifndef MODULE
 260static void sisfb_get_vga_mode_from_kernel(void)
 261{
 262#ifdef CONFIG_X86
 263        char mymode[32];
 264        int  mydepth = screen_info.lfb_depth;
 265
 266        if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
 267
 268        if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
 269            (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
 270            (mydepth >= 8) && (mydepth <= 32) ) {
 271
 272                if(mydepth == 24) mydepth = 32;
 273
 274                sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
 275                                        screen_info.lfb_height,
 276                                        mydepth);
 277
 278                printk(KERN_DEBUG
 279                        "sisfb: Using vga mode %s pre-set by kernel as default\n",
 280                        mymode);
 281
 282                sisfb_search_mode(mymode, true);
 283        }
 284#endif
 285        return;
 286}
 287#endif
 288
 289static void __init
 290sisfb_search_crt2type(const char *name)
 291{
 292        int i = 0;
 293
 294        /* We don't know the hardware specs yet and there is no ivideo */
 295
 296        if(name == NULL) return;
 297
 298        while(sis_crt2type[i].type_no != -1) {
 299                if(!strncasecmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
 300                        sisfb_crt2type = sis_crt2type[i].type_no;
 301                        sisfb_tvplug = sis_crt2type[i].tvplug_no;
 302                        sisfb_crt2flags = sis_crt2type[i].flags;
 303                        break;
 304                }
 305                i++;
 306        }
 307
 308        sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
 309        sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
 310
 311        if(sisfb_crt2type < 0)
 312                printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
 313}
 314
 315static void __init
 316sisfb_search_tvstd(const char *name)
 317{
 318        int i = 0;
 319
 320        /* We don't know the hardware specs yet and there is no ivideo */
 321
 322        if(name == NULL)
 323                return;
 324
 325        while(sis_tvtype[i].type_no != -1) {
 326                if(!strncasecmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
 327                        sisfb_tvstd = sis_tvtype[i].type_no;
 328                        break;
 329                }
 330                i++;
 331        }
 332}
 333
 334static void __init
 335sisfb_search_specialtiming(const char *name)
 336{
 337        int i = 0;
 338        bool found = false;
 339
 340        /* We don't know the hardware specs yet and there is no ivideo */
 341
 342        if(name == NULL)
 343                return;
 344
 345        if(!strncasecmp(name, "none", 4)) {
 346                sisfb_specialtiming = CUT_FORCENONE;
 347                printk(KERN_DEBUG "sisfb: Special timing disabled\n");
 348        } else {
 349                while(mycustomttable[i].chipID != 0) {
 350                        if(!strncasecmp(name,mycustomttable[i].optionName,
 351                           strlen(mycustomttable[i].optionName))) {
 352                                sisfb_specialtiming = mycustomttable[i].SpecialID;
 353                                found = true;
 354                                printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
 355                                        mycustomttable[i].vendorName,
 356                                        mycustomttable[i].cardName,
 357                                        mycustomttable[i].optionName);
 358                                break;
 359                        }
 360                        i++;
 361                }
 362                if(!found) {
 363                        printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
 364                        printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
 365                        i = 0;
 366                        while(mycustomttable[i].chipID != 0) {
 367                                printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
 368                                        mycustomttable[i].optionName,
 369                                        mycustomttable[i].vendorName,
 370                                        mycustomttable[i].cardName);
 371                                i++;
 372                        }
 373                }
 374        }
 375}
 376
 377/* ----------- Various detection routines ----------- */
 378
 379static void sisfb_detect_custom_timing(struct sis_video_info *ivideo)
 380{
 381        unsigned char *biosver = NULL;
 382        unsigned char *biosdate = NULL;
 383        bool footprint;
 384        u32 chksum = 0;
 385        int i, j;
 386
 387        if(ivideo->SiS_Pr.UseROM) {
 388                biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
 389                biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
 390                for(i = 0; i < 32768; i++)
 391                        chksum += ivideo->SiS_Pr.VirtualRomBase[i];
 392        }
 393
 394        i = 0;
 395        do {
 396                if( (mycustomttable[i].chipID == ivideo->chip)                  &&
 397                    ((!strlen(mycustomttable[i].biosversion)) ||
 398                     (ivideo->SiS_Pr.UseROM &&
 399                      (!strncmp(mycustomttable[i].biosversion, biosver,
 400                                strlen(mycustomttable[i].biosversion)))))       &&
 401                    ((!strlen(mycustomttable[i].biosdate)) ||
 402                     (ivideo->SiS_Pr.UseROM &&
 403                      (!strncmp(mycustomttable[i].biosdate, biosdate,
 404                                strlen(mycustomttable[i].biosdate)))))          &&
 405                    ((!mycustomttable[i].bioschksum) ||
 406                     (ivideo->SiS_Pr.UseROM &&
 407                      (mycustomttable[i].bioschksum == chksum)))                &&
 408                    (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
 409                    (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
 410                        footprint = true;
 411                        for(j = 0; j < 5; j++) {
 412                                if(mycustomttable[i].biosFootprintAddr[j]) {
 413                                        if(ivideo->SiS_Pr.UseROM) {
 414                                                if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
 415                                                        mycustomttable[i].biosFootprintData[j]) {
 416                                                        footprint = false;
 417                                                }
 418                                        } else
 419                                                footprint = false;
 420                                }
 421                        }
 422                        if(footprint) {
 423                                ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
 424                                printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
 425                                        mycustomttable[i].vendorName,
 426                                mycustomttable[i].cardName);
 427                                printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
 428                                        mycustomttable[i].optionName);
 429                                break;
 430                        }
 431                }
 432                i++;
 433        } while(mycustomttable[i].chipID);
 434}
 435
 436static bool sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
 437{
 438        int i, j, xres, yres, refresh, index;
 439        u32 emodes;
 440
 441        if(buffer[0] != 0x00 || buffer[1] != 0xff ||
 442           buffer[2] != 0xff || buffer[3] != 0xff ||
 443           buffer[4] != 0xff || buffer[5] != 0xff ||
 444           buffer[6] != 0xff || buffer[7] != 0x00) {
 445                printk(KERN_DEBUG "sisfb: Bad EDID header\n");
 446                return false;
 447        }
 448
 449        if(buffer[0x12] != 0x01) {
 450                printk(KERN_INFO "sisfb: EDID version %d not supported\n",
 451                        buffer[0x12]);
 452                return false;
 453        }
 454
 455        monitor->feature = buffer[0x18];
 456
 457        if(!(buffer[0x14] & 0x80)) {
 458                if(!(buffer[0x14] & 0x08)) {
 459                        printk(KERN_INFO
 460                                "sisfb: WARNING: Monitor does not support separate syncs\n");
 461                }
 462        }
 463
 464        if(buffer[0x13] >= 0x01) {
 465           /* EDID V1 rev 1 and 2: Search for monitor descriptor
 466            * to extract ranges
 467            */
 468            j = 0x36;
 469            for(i=0; i<4; i++) {
 470               if(buffer[j]     == 0x00 && buffer[j + 1] == 0x00 &&
 471                  buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
 472                  buffer[j + 4] == 0x00) {
 473                  monitor->hmin = buffer[j + 7];
 474                  monitor->hmax = buffer[j + 8];
 475                  monitor->vmin = buffer[j + 5];
 476                  monitor->vmax = buffer[j + 6];
 477                  monitor->dclockmax = buffer[j + 9] * 10 * 1000;
 478                  monitor->datavalid = true;
 479                  break;
 480               }
 481               j += 18;
 482            }
 483        }
 484
 485        if(!monitor->datavalid) {
 486           /* Otherwise: Get a range from the list of supported
 487            * Estabished Timings. This is not entirely accurate,
 488            * because fixed frequency monitors are not supported
 489            * that way.
 490            */
 491           monitor->hmin = 65535; monitor->hmax = 0;
 492           monitor->vmin = 65535; monitor->vmax = 0;
 493           monitor->dclockmax = 0;
 494           emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
 495           for(i = 0; i < 13; i++) {
 496              if(emodes & sisfb_ddcsmodes[i].mask) {
 497                 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
 498                 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
 499                 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
 500                 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
 501                 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
 502              }
 503           }
 504           index = 0x26;
 505           for(i = 0; i < 8; i++) {
 506              xres = (buffer[index] + 31) * 8;
 507              switch(buffer[index + 1] & 0xc0) {
 508                 case 0xc0: yres = (xres * 9) / 16; break;
 509                 case 0x80: yres = (xres * 4) /  5; break;
 510                 case 0x40: yres = (xres * 3) /  4; break;
 511                 default:   yres = xres;            break;
 512              }
 513              refresh = (buffer[index + 1] & 0x3f) + 60;
 514              if((xres >= 640) && (yres >= 480)) {
 515                 for(j = 0; j < 8; j++) {
 516                    if((xres == sisfb_ddcfmodes[j].x) &&
 517                       (yres == sisfb_ddcfmodes[j].y) &&
 518                       (refresh == sisfb_ddcfmodes[j].v)) {
 519                      if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
 520                      if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
 521                      if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
 522                      if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
 523                      if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
 524                    }
 525                 }
 526              }
 527              index += 2;
 528           }
 529           if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
 530              monitor->datavalid = true;
 531           }
 532        }
 533
 534        return monitor->datavalid;
 535}
 536
 537static void sisfb_handle_ddc(struct sis_video_info *ivideo,
 538                             struct sisfb_monitor *monitor, int crtno)
 539{
 540        unsigned short temp, i, realcrtno = crtno;
 541        unsigned char  buffer[256];
 542
 543        monitor->datavalid = false;
 544
 545        if(crtno) {
 546           if(ivideo->vbflags & CRT2_LCD)      realcrtno = 1;
 547           else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
 548           else return;
 549        }
 550
 551        if((ivideo->sisfb_crt1off) && (!crtno))
 552                return;
 553
 554        temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
 555                                realcrtno, 0, &buffer[0], ivideo->vbflags2);
 556        if((!temp) || (temp == 0xffff)) {
 557           printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
 558           return;
 559        } else {
 560           printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
 561           printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
 562                crtno + 1,
 563                (temp & 0x1a) ? "" : "[none of the supported]",
 564                (temp & 0x02) ? "2 " : "",
 565                (temp & 0x08) ? "D&P" : "",
 566                (temp & 0x10) ? "FPDI-2" : "");
 567           if(temp & 0x02) {
 568              i = 3;  /* Number of retrys */
 569              do {
 570                 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
 571                                     realcrtno, 1, &buffer[0], ivideo->vbflags2);
 572              } while((temp) && i--);
 573              if(!temp) {
 574                 if(sisfb_interpret_edid(monitor, &buffer[0])) {
 575                    printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
 576                        monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
 577                        monitor->dclockmax / 1000);
 578                 } else {
 579                    printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
 580                 }
 581              } else {
 582                 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
 583              }
 584           } else {
 585              printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
 586           }
 587        }
 588}
 589
 590/* -------------- Mode validation --------------- */
 591
 592static bool
 593sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
 594                int mode_idx, int rate_idx, int rate)
 595{
 596        int htotal, vtotal;
 597        unsigned int dclock, hsync;
 598
 599        if(!monitor->datavalid)
 600                return true;
 601
 602        if(mode_idx < 0)
 603                return false;
 604
 605        /* Skip for 320x200, 320x240, 640x400 */
 606        switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
 607        case 0x59:
 608        case 0x41:
 609        case 0x4f:
 610        case 0x50:
 611        case 0x56:
 612        case 0x53:
 613        case 0x2f:
 614        case 0x5d:
 615        case 0x5e:
 616                return true;
 617#ifdef CONFIG_FB_SIS_315
 618        case 0x5a:
 619        case 0x5b:
 620                if(ivideo->sisvga_engine == SIS_315_VGA) return true;
 621#endif
 622        }
 623
 624        if(rate < (monitor->vmin - 1))
 625                return false;
 626        if(rate > (monitor->vmax + 1))
 627                return false;
 628
 629        if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
 630                                  sisbios_mode[mode_idx].mode_no[ivideo->mni],
 631                                  &htotal, &vtotal, rate_idx)) {
 632                dclock = (htotal * vtotal * rate) / 1000;
 633                if(dclock > (monitor->dclockmax + 1000))
 634                        return false;
 635                hsync = dclock / htotal;
 636                if(hsync < (monitor->hmin - 1))
 637                        return false;
 638                if(hsync > (monitor->hmax + 1))
 639                        return false;
 640        } else {
 641                return false;
 642        }
 643        return true;
 644}
 645
 646static int
 647sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
 648{
 649        u16 xres=0, yres, myres;
 650
 651#ifdef CONFIG_FB_SIS_300
 652        if(ivideo->sisvga_engine == SIS_300_VGA) {
 653                if(!(sisbios_mode[myindex].chipset & MD_SIS300))
 654                        return -1 ;
 655        }
 656#endif
 657#ifdef CONFIG_FB_SIS_315
 658        if(ivideo->sisvga_engine == SIS_315_VGA) {
 659                if(!(sisbios_mode[myindex].chipset & MD_SIS315))
 660                        return -1;
 661        }
 662#endif
 663
 664        myres = sisbios_mode[myindex].yres;
 665
 666        switch(vbflags & VB_DISPTYPE_DISP2) {
 667
 668        case CRT2_LCD:
 669                xres = ivideo->lcdxres; yres = ivideo->lcdyres;
 670
 671                if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
 672                   (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
 673                        if(sisbios_mode[myindex].xres > xres)
 674                                return -1;
 675                        if(myres > yres)
 676                                return -1;
 677                }
 678
 679                if(ivideo->sisfb_fstn) {
 680                        if(sisbios_mode[myindex].xres == 320) {
 681                                if(myres == 240) {
 682                                        switch(sisbios_mode[myindex].mode_no[1]) {
 683                                                case 0x50: myindex = MODE_FSTN_8;  break;
 684                                                case 0x56: myindex = MODE_FSTN_16; break;
 685                                                case 0x53: return -1;
 686                                        }
 687                                }
 688                        }
 689                }
 690
 691                if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
 692                                sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
 693                                ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
 694                        return -1;
 695                }
 696                break;
 697
 698        case CRT2_TV:
 699                if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
 700                                sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
 701                        return -1;
 702                }
 703                break;
 704
 705        case CRT2_VGA:
 706                if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
 707                                sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
 708                        return -1;
 709                }
 710                break;
 711        }
 712
 713        return myindex;
 714}
 715
 716static u8
 717sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
 718{
 719        int i = 0;
 720        u16 xres = sisbios_mode[mode_idx].xres;
 721        u16 yres = sisbios_mode[mode_idx].yres;
 722
 723        ivideo->rate_idx = 0;
 724        while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
 725                if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
 726                        if(sisfb_vrate[i].refresh == rate) {
 727                                ivideo->rate_idx = sisfb_vrate[i].idx;
 728                                break;
 729                        } else if(sisfb_vrate[i].refresh > rate) {
 730                                if((sisfb_vrate[i].refresh - rate) <= 3) {
 731                                        DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
 732                                                rate, sisfb_vrate[i].refresh);
 733                                        ivideo->rate_idx = sisfb_vrate[i].idx;
 734                                        ivideo->refresh_rate = sisfb_vrate[i].refresh;
 735                                } else if((sisfb_vrate[i].idx != 1) &&
 736                                                ((rate - sisfb_vrate[i-1].refresh) <= 2)) {
 737                                        DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
 738                                                rate, sisfb_vrate[i-1].refresh);
 739                                        ivideo->rate_idx = sisfb_vrate[i-1].idx;
 740                                        ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
 741                                }
 742                                break;
 743                        } else if((rate - sisfb_vrate[i].refresh) <= 2) {
 744                                DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
 745                                                rate, sisfb_vrate[i].refresh);
 746                                ivideo->rate_idx = sisfb_vrate[i].idx;
 747                                break;
 748                        }
 749                }
 750                i++;
 751        }
 752        if(ivideo->rate_idx > 0) {
 753                return ivideo->rate_idx;
 754        } else {
 755                printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
 756                                rate, xres, yres);
 757                return 0;
 758        }
 759}
 760
 761static bool
 762sisfb_bridgeisslave(struct sis_video_info *ivideo)
 763{
 764        unsigned char P1_00;
 765
 766        if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
 767                return false;
 768
 769        P1_00 = SiS_GetReg(SISPART1, 0x00);
 770        if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
 771            ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
 772                return true;
 773        } else {
 774                return false;
 775        }
 776}
 777
 778static bool
 779sisfballowretracecrt1(struct sis_video_info *ivideo)
 780{
 781        u8 temp;
 782
 783        temp = SiS_GetReg(SISCR, 0x17);
 784        if(!(temp & 0x80))
 785                return false;
 786
 787        temp = SiS_GetReg(SISSR, 0x1f);
 788        if(temp & 0xc0)
 789                return false;
 790
 791        return true;
 792}
 793
 794static bool
 795sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
 796{
 797        if(!sisfballowretracecrt1(ivideo))
 798                return false;
 799
 800        if (SiS_GetRegByte(SISINPSTAT) & 0x08)
 801                return true;
 802        else
 803                return false;
 804}
 805
 806static void
 807sisfbwaitretracecrt1(struct sis_video_info *ivideo)
 808{
 809        int watchdog;
 810
 811        if(!sisfballowretracecrt1(ivideo))
 812                return;
 813
 814        watchdog = 65536;
 815        while ((!(SiS_GetRegByte(SISINPSTAT) & 0x08)) && --watchdog);
 816        watchdog = 65536;
 817        while ((SiS_GetRegByte(SISINPSTAT) & 0x08) && --watchdog);
 818}
 819
 820static bool
 821sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
 822{
 823        unsigned char temp, reg;
 824
 825        switch(ivideo->sisvga_engine) {
 826        case SIS_300_VGA: reg = 0x25; break;
 827        case SIS_315_VGA: reg = 0x30; break;
 828        default:          return false;
 829        }
 830
 831        temp = SiS_GetReg(SISPART1, reg);
 832        if(temp & 0x02)
 833                return true;
 834        else
 835                return false;
 836}
 837
 838static bool
 839sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
 840{
 841        if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
 842                if(!sisfb_bridgeisslave(ivideo)) {
 843                        return sisfbcheckvretracecrt2(ivideo);
 844                }
 845        }
 846        return sisfbcheckvretracecrt1(ivideo);
 847}
 848
 849static u32
 850sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
 851{
 852        u8 idx, reg1, reg2, reg3, reg4;
 853        u32 ret = 0;
 854
 855        (*vcount) = (*hcount) = 0;
 856
 857        if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
 858
 859                ret |= (FB_VBLANK_HAVE_VSYNC  |
 860                        FB_VBLANK_HAVE_HBLANK |
 861                        FB_VBLANK_HAVE_VBLANK |
 862                        FB_VBLANK_HAVE_VCOUNT |
 863                        FB_VBLANK_HAVE_HCOUNT);
 864                switch(ivideo->sisvga_engine) {
 865                        case SIS_300_VGA: idx = 0x25; break;
 866                        default:
 867                        case SIS_315_VGA: idx = 0x30; break;
 868                }
 869                reg1 = SiS_GetReg(SISPART1, (idx+0)); /* 30 */
 870                reg2 = SiS_GetReg(SISPART1, (idx+1)); /* 31 */
 871                reg3 = SiS_GetReg(SISPART1, (idx+2)); /* 32 */
 872                reg4 = SiS_GetReg(SISPART1, (idx+3)); /* 33 */
 873                if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
 874                if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
 875                if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
 876                (*vcount) = reg3 | ((reg4 & 0x70) << 4);
 877                (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
 878
 879        } else if(sisfballowretracecrt1(ivideo)) {
 880
 881                ret |= (FB_VBLANK_HAVE_VSYNC  |
 882                        FB_VBLANK_HAVE_VBLANK |
 883                        FB_VBLANK_HAVE_VCOUNT |
 884                        FB_VBLANK_HAVE_HCOUNT);
 885                reg1 = SiS_GetRegByte(SISINPSTAT);
 886                if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
 887                if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
 888                reg1 = SiS_GetReg(SISCR, 0x20);
 889                reg1 = SiS_GetReg(SISCR, 0x1b);
 890                reg2 = SiS_GetReg(SISCR, 0x1c);
 891                reg3 = SiS_GetReg(SISCR, 0x1d);
 892                (*vcount) = reg2 | ((reg3 & 0x07) << 8);
 893                (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
 894        }
 895
 896        return ret;
 897}
 898
 899static int
 900sisfb_myblank(struct sis_video_info *ivideo, int blank)
 901{
 902        u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
 903        bool backlight = true;
 904
 905        switch(blank) {
 906                case FB_BLANK_UNBLANK:  /* on */
 907                        sr01  = 0x00;
 908                        sr11  = 0x00;
 909                        sr1f  = 0x00;
 910                        cr63  = 0x00;
 911                        p2_0  = 0x20;
 912                        p1_13 = 0x00;
 913                        backlight = true;
 914                        break;
 915                case FB_BLANK_NORMAL:   /* blank */
 916                        sr01  = 0x20;
 917                        sr11  = 0x00;
 918                        sr1f  = 0x00;
 919                        cr63  = 0x00;
 920                        p2_0  = 0x20;
 921                        p1_13 = 0x00;
 922                        backlight = true;
 923                        break;
 924                case FB_BLANK_VSYNC_SUSPEND:    /* no vsync */
 925                        sr01  = 0x20;
 926                        sr11  = 0x08;
 927                        sr1f  = 0x80;
 928                        cr63  = 0x40;
 929                        p2_0  = 0x40;
 930                        p1_13 = 0x80;
 931                        backlight = false;
 932                        break;
 933                case FB_BLANK_HSYNC_SUSPEND:    /* no hsync */
 934                        sr01  = 0x20;
 935                        sr11  = 0x08;
 936                        sr1f  = 0x40;
 937                        cr63  = 0x40;
 938                        p2_0  = 0x80;
 939                        p1_13 = 0x40;
 940                        backlight = false;
 941                        break;
 942                case FB_BLANK_POWERDOWN:        /* off */
 943                        sr01  = 0x20;
 944                        sr11  = 0x08;
 945                        sr1f  = 0xc0;
 946                        cr63  = 0x40;
 947                        p2_0  = 0xc0;
 948                        p1_13 = 0xc0;
 949                        backlight = false;
 950                        break;
 951                default:
 952                        return 1;
 953        }
 954
 955        if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
 956
 957                if( (!ivideo->sisfb_thismonitor.datavalid) ||
 958                    ((ivideo->sisfb_thismonitor.datavalid) &&
 959                     (ivideo->sisfb_thismonitor.feature & 0xe0))) {
 960
 961                        if(ivideo->sisvga_engine == SIS_315_VGA) {
 962                                SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
 963                        }
 964
 965                        if(!(sisfb_bridgeisslave(ivideo))) {
 966                                SiS_SetRegANDOR(SISSR, 0x01, ~0x20, sr01);
 967                                SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, sr1f);
 968                        }
 969                }
 970
 971        }
 972
 973        if(ivideo->currentvbflags & CRT2_LCD) {
 974
 975                if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
 976                        if(backlight) {
 977                                SiS_SiS30xBLOn(&ivideo->SiS_Pr);
 978                        } else {
 979                                SiS_SiS30xBLOff(&ivideo->SiS_Pr);
 980                        }
 981                } else if(ivideo->sisvga_engine == SIS_315_VGA) {
 982#ifdef CONFIG_FB_SIS_315
 983                        if(ivideo->vbflags2 & VB2_CHRONTEL) {
 984                                if(backlight) {
 985                                        SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
 986                                } else {
 987                                        SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
 988                                }
 989                        }
 990#endif
 991                }
 992
 993                if(((ivideo->sisvga_engine == SIS_300_VGA) &&
 994                    (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
 995                   ((ivideo->sisvga_engine == SIS_315_VGA) &&
 996                    ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
 997                        SiS_SetRegANDOR(SISSR, 0x11, ~0x0c, sr11);
 998                }
 999
1000                if(ivideo->sisvga_engine == SIS_300_VGA) {
1001                        if((ivideo->vbflags2 & VB2_30xB) &&
1002                           (!(ivideo->vbflags2 & VB2_30xBDH))) {
1003                                SiS_SetRegANDOR(SISPART1, 0x13, 0x3f, p1_13);
1004                        }
1005                } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1006                        if((ivideo->vbflags2 & VB2_30xB) &&
1007                           (!(ivideo->vbflags2 & VB2_30xBDH))) {
1008                                SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
1009                        }
1010                }
1011
1012        } else if(ivideo->currentvbflags & CRT2_VGA) {
1013
1014                if(ivideo->vbflags2 & VB2_30xB) {
1015                        SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
1016                }
1017
1018        }
1019
1020        return 0;
1021}
1022
1023/* ------------- Callbacks from init.c/init301.c  -------------- */
1024
1025#ifdef CONFIG_FB_SIS_300
1026unsigned int
1027sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1028{
1029   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1030   u32 val = 0;
1031
1032   pci_read_config_dword(ivideo->nbridge, reg, &val);
1033   return (unsigned int)val;
1034}
1035
1036void
1037sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1038{
1039   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1040
1041   pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1042}
1043
1044unsigned int
1045sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1046{
1047   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1048   u32 val = 0;
1049
1050   if(!ivideo->lpcdev) return 0;
1051
1052   pci_read_config_dword(ivideo->lpcdev, reg, &val);
1053   return (unsigned int)val;
1054}
1055#endif
1056
1057#ifdef CONFIG_FB_SIS_315
1058void
1059sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1060{
1061   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1062
1063   pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1064}
1065
1066unsigned int
1067sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1068{
1069   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1070   u16 val = 0;
1071
1072   if(!ivideo->lpcdev) return 0;
1073
1074   pci_read_config_word(ivideo->lpcdev, reg, &val);
1075   return (unsigned int)val;
1076}
1077#endif
1078
1079/* ----------- FBDev related routines for all series ----------- */
1080
1081static int
1082sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1083{
1084        return (var->bits_per_pixel == 8) ? 256 : 16;
1085}
1086
1087static void
1088sisfb_set_vparms(struct sis_video_info *ivideo)
1089{
1090        switch(ivideo->video_bpp) {
1091        case 8:
1092                ivideo->DstColor = 0x0000;
1093                ivideo->SiS310_AccelDepth = 0x00000000;
1094                ivideo->video_cmap_len = 256;
1095                break;
1096        case 16:
1097                ivideo->DstColor = 0x8000;
1098                ivideo->SiS310_AccelDepth = 0x00010000;
1099                ivideo->video_cmap_len = 16;
1100                break;
1101        case 32:
1102                ivideo->DstColor = 0xC000;
1103                ivideo->SiS310_AccelDepth = 0x00020000;
1104                ivideo->video_cmap_len = 16;
1105                break;
1106        default:
1107                ivideo->video_cmap_len = 16;
1108                printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1109                ivideo->accel = 0;
1110        }
1111}
1112
1113static int
1114sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1115{
1116        int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
1117
1118        if(maxyres > 32767) maxyres = 32767;
1119
1120        return maxyres;
1121}
1122
1123static void
1124sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1125{
1126        ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1127        ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1128        if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1129                if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1130                        ivideo->scrnpitchCRT1 <<= 1;
1131                }
1132        }
1133}
1134
1135static void
1136sisfb_set_pitch(struct sis_video_info *ivideo)
1137{
1138        bool isslavemode = false;
1139        unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1140        unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1141
1142        if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
1143
1144        /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1145        if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1146                SiS_SetReg(SISCR, 0x13, (HDisplay1 & 0xFF));
1147                SiS_SetRegANDOR(SISSR, 0x0E, 0xF0, (HDisplay1 >> 8));
1148        }
1149
1150        /* We must not set the pitch for CRT2 if bridge is in slave mode */
1151        if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1152                SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
1153                SiS_SetReg(SISPART1, 0x07, (HDisplay2 & 0xFF));
1154                SiS_SetRegANDOR(SISPART1, 0x09, 0xF0, (HDisplay2 >> 8));
1155        }
1156}
1157
1158static void
1159sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1160{
1161        ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1162
1163        switch(var->bits_per_pixel) {
1164        case 8:
1165                var->red.offset = var->green.offset = var->blue.offset = 0;
1166                var->red.length = var->green.length = var->blue.length = 8;
1167                break;
1168        case 16:
1169                var->red.offset = 11;
1170                var->red.length = 5;
1171                var->green.offset = 5;
1172                var->green.length = 6;
1173                var->blue.offset = 0;
1174                var->blue.length = 5;
1175                var->transp.offset = 0;
1176                var->transp.length = 0;
1177                break;
1178        case 32:
1179                var->red.offset = 16;
1180                var->red.length = 8;
1181                var->green.offset = 8;
1182                var->green.length = 8;
1183                var->blue.offset = 0;
1184                var->blue.length = 8;
1185                var->transp.offset = 24;
1186                var->transp.length = 8;
1187                break;
1188        }
1189}
1190
1191static int
1192sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1193{
1194        unsigned short modeno = ivideo->mode_no;
1195
1196        /* >=2.6.12's fbcon clears the screen anyway */
1197        modeno |= 0x80;
1198
1199        SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1200
1201        sisfb_pre_setmode(ivideo);
1202
1203        if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
1204                printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1205                return -EINVAL;
1206        }
1207
1208        SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1209
1210        sisfb_post_setmode(ivideo);
1211
1212        return 0;
1213}
1214
1215
1216static int
1217sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1218{
1219        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1220        unsigned int htotal = 0, vtotal = 0;
1221        unsigned int drate = 0, hrate = 0;
1222        int found_mode = 0, ret;
1223        int old_mode;
1224        u32 pixclock;
1225
1226        htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1227
1228        vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1229
1230        pixclock = var->pixclock;
1231
1232        if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1233                vtotal += var->yres;
1234                vtotal <<= 1;
1235        } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1236                vtotal += var->yres;
1237                vtotal <<= 2;
1238        } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1239                vtotal += var->yres;
1240                vtotal <<= 1;
1241        } else  vtotal += var->yres;
1242
1243        if(!(htotal) || !(vtotal)) {
1244                DPRINTK("sisfb: Invalid 'var' information\n");
1245                return -EINVAL;
1246        }
1247
1248        if(pixclock && htotal && vtotal) {
1249                drate = 1000000000 / pixclock;
1250                hrate = (drate * 1000) / htotal;
1251                ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1252        } else {
1253                ivideo->refresh_rate = 60;
1254        }
1255
1256        old_mode = ivideo->sisfb_mode_idx;
1257        ivideo->sisfb_mode_idx = 0;
1258
1259        while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1260               (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1261                if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1262                    (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1263                    (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1264                        ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1265                        found_mode = 1;
1266                        break;
1267                }
1268                ivideo->sisfb_mode_idx++;
1269        }
1270
1271        if(found_mode) {
1272                ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1273                                ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1274        } else {
1275                ivideo->sisfb_mode_idx = -1;
1276        }
1277
1278        if(ivideo->sisfb_mode_idx < 0) {
1279                printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1280                       var->yres, var->bits_per_pixel);
1281                ivideo->sisfb_mode_idx = old_mode;
1282                return -EINVAL;
1283        }
1284
1285        ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1286
1287        if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1288                ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1289                ivideo->refresh_rate = 60;
1290        }
1291
1292        if(isactive) {
1293                /* If acceleration to be used? Need to know
1294                 * before pre/post_set_mode()
1295                 */
1296                ivideo->accel = 0;
1297#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1298#ifdef STUPID_ACCELF_TEXT_SHIT
1299                if(var->accel_flags & FB_ACCELF_TEXT) {
1300                        info->flags &= ~FBINFO_HWACCEL_DISABLED;
1301                } else {
1302                        info->flags |= FBINFO_HWACCEL_DISABLED;
1303                }
1304#endif
1305                if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1306#else
1307                if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1308#endif
1309
1310                if((ret = sisfb_set_mode(ivideo, 1))) {
1311                        return ret;
1312                }
1313
1314                ivideo->video_bpp    = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1315                ivideo->video_width  = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1316                ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1317
1318                sisfb_calc_pitch(ivideo, var);
1319                sisfb_set_pitch(ivideo);
1320
1321                sisfb_set_vparms(ivideo);
1322
1323                ivideo->current_width = ivideo->video_width;
1324                ivideo->current_height = ivideo->video_height;
1325                ivideo->current_bpp = ivideo->video_bpp;
1326                ivideo->current_htotal = htotal;
1327                ivideo->current_vtotal = vtotal;
1328                ivideo->current_linelength = ivideo->video_linelength;
1329                ivideo->current_pixclock = var->pixclock;
1330                ivideo->current_refresh_rate = ivideo->refresh_rate;
1331                ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1332        }
1333
1334        return 0;
1335}
1336
1337static void
1338sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1339{
1340        SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1341
1342        SiS_SetReg(SISCR, 0x0D, base & 0xFF);
1343        SiS_SetReg(SISCR, 0x0C, (base >> 8) & 0xFF);
1344        SiS_SetReg(SISSR, 0x0D, (base >> 16) & 0xFF);
1345        if(ivideo->sisvga_engine == SIS_315_VGA) {
1346                SiS_SetRegANDOR(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1347        }
1348}
1349
1350static void
1351sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1352{
1353        if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1354                SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
1355                SiS_SetReg(SISPART1, 0x06, (base & 0xFF));
1356                SiS_SetReg(SISPART1, 0x05, ((base >> 8) & 0xFF));
1357                SiS_SetReg(SISPART1, 0x04, ((base >> 16) & 0xFF));
1358                if(ivideo->sisvga_engine == SIS_315_VGA) {
1359                        SiS_SetRegANDOR(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1360                }
1361        }
1362}
1363
1364static int
1365sisfb_pan_var(struct sis_video_info *ivideo, struct fb_info *info,
1366              struct fb_var_screeninfo *var)
1367{
1368        ivideo->current_base = var->yoffset * info->var.xres_virtual
1369                             + var->xoffset;
1370
1371        /* calculate base bpp dep. */
1372        switch (info->var.bits_per_pixel) {
1373        case 32:
1374                break;
1375        case 16:
1376                ivideo->current_base >>= 1;
1377                break;
1378        case 8:
1379        default:
1380                ivideo->current_base >>= 2;
1381                break;
1382        }
1383
1384        ivideo->current_base += (ivideo->video_offset >> 2);
1385
1386        sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1387        sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1388
1389        return 0;
1390}
1391
1392static int
1393sisfb_open(struct fb_info *info, int user)
1394{
1395        return 0;
1396}
1397
1398static int
1399sisfb_release(struct fb_info *info, int user)
1400{
1401        return 0;
1402}
1403
1404static int
1405sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1406                unsigned transp, struct fb_info *info)
1407{
1408        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1409
1410        if(regno >= sisfb_get_cmap_len(&info->var))
1411                return 1;
1412
1413        switch(info->var.bits_per_pixel) {
1414        case 8:
1415                SiS_SetRegByte(SISDACA, regno);
1416                SiS_SetRegByte(SISDACD, (red >> 10));
1417                SiS_SetRegByte(SISDACD, (green >> 10));
1418                SiS_SetRegByte(SISDACD, (blue >> 10));
1419                if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1420                        SiS_SetRegByte(SISDAC2A, regno);
1421                        SiS_SetRegByte(SISDAC2D, (red >> 8));
1422                        SiS_SetRegByte(SISDAC2D, (green >> 8));
1423                        SiS_SetRegByte(SISDAC2D, (blue >> 8));
1424                }
1425                break;
1426        case 16:
1427                if (regno >= 16)
1428                        break;
1429
1430                ((u32 *)(info->pseudo_palette))[regno] =
1431                                (red & 0xf800)          |
1432                                ((green & 0xfc00) >> 5) |
1433                                ((blue & 0xf800) >> 11);
1434                break;
1435        case 32:
1436                if (regno >= 16)
1437                        break;
1438
1439                red >>= 8;
1440                green >>= 8;
1441                blue >>= 8;
1442                ((u32 *)(info->pseudo_palette))[regno] =
1443                                (red << 16) | (green << 8) | (blue);
1444                break;
1445        }
1446        return 0;
1447}
1448
1449static int
1450sisfb_set_par(struct fb_info *info)
1451{
1452        int err;
1453
1454        if((err = sisfb_do_set_var(&info->var, 1, info)))
1455                return err;
1456
1457        sisfb_get_fix(&info->fix, -1, info);
1458
1459        return 0;
1460}
1461
1462static int
1463sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1464{
1465        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1466        unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1467        unsigned int drate = 0, hrate = 0, maxyres;
1468        int found_mode = 0;
1469        int refresh_rate, search_idx, tidx;
1470        bool recalc_clock = false;
1471        u32 pixclock;
1472
1473        htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1474
1475        vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1476
1477        pixclock = var->pixclock;
1478
1479        if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1480                vtotal += var->yres;
1481                vtotal <<= 1;
1482        } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1483                vtotal += var->yres;
1484                vtotal <<= 2;
1485        } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1486                vtotal += var->yres;
1487                vtotal <<= 1;
1488        } else
1489                vtotal += var->yres;
1490
1491        if(!(htotal) || !(vtotal)) {
1492                SISFAIL("sisfb: no valid timing data");
1493        }
1494
1495        search_idx = 0;
1496        while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1497               (sisbios_mode[search_idx].xres <= var->xres) ) {
1498                if( (sisbios_mode[search_idx].xres == var->xres) &&
1499                    (sisbios_mode[search_idx].yres == var->yres) &&
1500                    (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1501                        if((tidx = sisfb_validate_mode(ivideo, search_idx,
1502                                                ivideo->currentvbflags)) > 0) {
1503                                found_mode = 1;
1504                                search_idx = tidx;
1505                                break;
1506                        }
1507                }
1508                search_idx++;
1509        }
1510
1511        if(!found_mode) {
1512                search_idx = 0;
1513                while(sisbios_mode[search_idx].mode_no[0] != 0) {
1514                   if( (var->xres <= sisbios_mode[search_idx].xres) &&
1515                       (var->yres <= sisbios_mode[search_idx].yres) &&
1516                       (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1517                        if((tidx = sisfb_validate_mode(ivideo,search_idx,
1518                                                ivideo->currentvbflags)) > 0) {
1519                                found_mode = 1;
1520                                search_idx = tidx;
1521                                break;
1522                        }
1523                   }
1524                   search_idx++;
1525                }
1526                if(found_mode) {
1527                        printk(KERN_DEBUG
1528                                "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1529                                var->xres, var->yres, var->bits_per_pixel,
1530                                sisbios_mode[search_idx].xres,
1531                                sisbios_mode[search_idx].yres,
1532                                var->bits_per_pixel);
1533                        var->xres = sisbios_mode[search_idx].xres;
1534                        var->yres = sisbios_mode[search_idx].yres;
1535                } else {
1536                        printk(KERN_ERR
1537                                "sisfb: Failed to find supported mode near %dx%dx%d\n",
1538                                var->xres, var->yres, var->bits_per_pixel);
1539                        return -EINVAL;
1540                }
1541        }
1542
1543        if( ((ivideo->vbflags2 & VB2_LVDS) ||
1544             ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1545            (var->bits_per_pixel == 8) ) {
1546                /* Slave modes on LVDS and 301B-DH */
1547                refresh_rate = 60;
1548                recalc_clock = true;
1549        } else if( (ivideo->current_htotal == htotal) &&
1550                   (ivideo->current_vtotal == vtotal) &&
1551                   (ivideo->current_pixclock == pixclock) ) {
1552                /* x=x & y=y & c=c -> assume depth change */
1553                drate = 1000000000 / pixclock;
1554                hrate = (drate * 1000) / htotal;
1555                refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1556        } else if( ( (ivideo->current_htotal != htotal) ||
1557                     (ivideo->current_vtotal != vtotal) ) &&
1558                   (ivideo->current_pixclock == var->pixclock) ) {
1559                /* x!=x | y!=y & c=c -> invalid pixclock */
1560                if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1561                        refresh_rate =
1562                                ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1563                } else if(ivideo->sisfb_parm_rate != -1) {
1564                        /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1565                        refresh_rate = ivideo->sisfb_parm_rate;
1566                } else {
1567                        refresh_rate = 60;
1568                }
1569                recalc_clock = true;
1570        } else if((pixclock) && (htotal) && (vtotal)) {
1571                drate = 1000000000 / pixclock;
1572                hrate = (drate * 1000) / htotal;
1573                refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1574        } else if(ivideo->current_refresh_rate) {
1575                refresh_rate = ivideo->current_refresh_rate;
1576                recalc_clock = true;
1577        } else {
1578                refresh_rate = 60;
1579                recalc_clock = true;
1580        }
1581
1582        myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1583
1584        /* Eventually recalculate timing and clock */
1585        if(recalc_clock) {
1586                if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1587                var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1588                                                sisbios_mode[search_idx].mode_no[ivideo->mni],
1589                                                myrateindex));
1590                sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1591                                        sisbios_mode[search_idx].mode_no[ivideo->mni],
1592                                        myrateindex, var);
1593                if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1594                        var->pixclock <<= 1;
1595                }
1596        }
1597
1598        if(ivideo->sisfb_thismonitor.datavalid) {
1599                if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1600                                myrateindex, refresh_rate)) {
1601                        printk(KERN_INFO
1602                                "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1603                }
1604        }
1605
1606        /* Adapt RGB settings */
1607        sisfb_bpp_to_var(ivideo, var);
1608
1609        if(var->xres > var->xres_virtual)
1610                var->xres_virtual = var->xres;
1611
1612        if(ivideo->sisfb_ypan) {
1613                maxyres = sisfb_calc_maxyres(ivideo, var);
1614                if(ivideo->sisfb_max) {
1615                        var->yres_virtual = maxyres;
1616                } else {
1617                        if(var->yres_virtual > maxyres) {
1618                                var->yres_virtual = maxyres;
1619                        }
1620                }
1621                if(var->yres_virtual <= var->yres) {
1622                        var->yres_virtual = var->yres;
1623                }
1624        } else {
1625                if(var->yres != var->yres_virtual) {
1626                        var->yres_virtual = var->yres;
1627                }
1628                var->xoffset = 0;
1629                var->yoffset = 0;
1630        }
1631
1632        /* Truncate offsets to maximum if too high */
1633        if(var->xoffset > var->xres_virtual - var->xres) {
1634                var->xoffset = var->xres_virtual - var->xres - 1;
1635        }
1636
1637        if(var->yoffset > var->yres_virtual - var->yres) {
1638                var->yoffset = var->yres_virtual - var->yres - 1;
1639        }
1640
1641        /* Set everything else to 0 */
1642        var->red.msb_right =
1643                var->green.msb_right =
1644                var->blue.msb_right =
1645                var->transp.offset =
1646                var->transp.length =
1647                var->transp.msb_right = 0;
1648
1649        return 0;
1650}
1651
1652static int
1653sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1654{
1655        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1656        int err;
1657
1658        if (var->vmode & FB_VMODE_YWRAP)
1659                return -EINVAL;
1660
1661        if (var->xoffset + info->var.xres > info->var.xres_virtual ||
1662            var->yoffset + info->var.yres > info->var.yres_virtual)
1663                return -EINVAL;
1664
1665        err = sisfb_pan_var(ivideo, info, var);
1666        if (err < 0)
1667                return err;
1668
1669        info->var.xoffset = var->xoffset;
1670        info->var.yoffset = var->yoffset;
1671
1672        return 0;
1673}
1674
1675static int
1676sisfb_blank(int blank, struct fb_info *info)
1677{
1678        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1679
1680        return sisfb_myblank(ivideo, blank);
1681}
1682
1683/* ----------- FBDev related routines for all series ---------- */
1684
1685static int      sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1686                            unsigned long arg)
1687{
1688        struct sis_video_info   *ivideo = (struct sis_video_info *)info->par;
1689        struct sis_memreq       sismemreq;
1690        struct fb_vblank        sisvbblank;
1691        u32                     gpu32 = 0;
1692#ifndef __user
1693#define __user
1694#endif
1695        u32 __user              *argp = (u32 __user *)arg;
1696
1697        switch(cmd) {
1698           case FBIO_ALLOC:
1699                if(!capable(CAP_SYS_RAWIO))
1700                        return -EPERM;
1701
1702                if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1703                        return -EFAULT;
1704
1705                sis_malloc(&sismemreq);
1706
1707                if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1708                        sis_free((u32)sismemreq.offset);
1709                        return -EFAULT;
1710                }
1711                break;
1712
1713           case FBIO_FREE:
1714                if(!capable(CAP_SYS_RAWIO))
1715                        return -EPERM;
1716
1717                if(get_user(gpu32, argp))
1718                        return -EFAULT;
1719
1720                sis_free(gpu32);
1721                break;
1722
1723           case FBIOGET_VBLANK:
1724
1725                memset(&sisvbblank, 0, sizeof(struct fb_vblank));
1726
1727                sisvbblank.count = 0;
1728                sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1729
1730                if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1731                        return -EFAULT;
1732
1733                break;
1734
1735           case SISFB_GET_INFO_SIZE:
1736                return put_user(sizeof(struct sisfb_info), argp);
1737
1738           case SISFB_GET_INFO_OLD:
1739                if(ivideo->warncount++ < 10)
1740                        printk(KERN_INFO
1741                                "sisfb: Deprecated ioctl call received - update your application!\n");
1742                /* fall through */
1743           case SISFB_GET_INFO:  /* For communication with X driver */
1744                ivideo->sisfb_infoblock.sisfb_id         = SISFB_ID;
1745                ivideo->sisfb_infoblock.sisfb_version    = VER_MAJOR;
1746                ivideo->sisfb_infoblock.sisfb_revision   = VER_MINOR;
1747                ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1748                ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1749                ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1750                ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1751                ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1752                if(ivideo->modechanged) {
1753                        ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1754                } else {
1755                        ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1756                }
1757                ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1758                ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1759                ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1760                ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1761                ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1762                ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1763                ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1764                ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1765                ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1766                ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1767                ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1768                ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1769                ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1770                ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1771                ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1772                ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1773                ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1774                ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1775                ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1776                ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1777                ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1778                ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1779                ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1780                ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1781                ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1782                ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1783                ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1784                ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1785
1786                if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1787                                                sizeof(ivideo->sisfb_infoblock)))
1788                        return -EFAULT;
1789
1790                break;
1791
1792           case SISFB_GET_VBRSTATUS_OLD:
1793                if(ivideo->warncount++ < 10)
1794                        printk(KERN_INFO
1795                                "sisfb: Deprecated ioctl call received - update your application!\n");
1796                /* fall through */
1797           case SISFB_GET_VBRSTATUS:
1798                if(sisfb_CheckVBRetrace(ivideo))
1799                        return put_user((u32)1, argp);
1800                else
1801                        return put_user((u32)0, argp);
1802
1803           case SISFB_GET_AUTOMAXIMIZE_OLD:
1804                if(ivideo->warncount++ < 10)
1805                        printk(KERN_INFO
1806                                "sisfb: Deprecated ioctl call received - update your application!\n");
1807                /* fall through */
1808           case SISFB_GET_AUTOMAXIMIZE:
1809                if(ivideo->sisfb_max)
1810                        return put_user((u32)1, argp);
1811                else
1812                        return put_user((u32)0, argp);
1813
1814           case SISFB_SET_AUTOMAXIMIZE_OLD:
1815                if(ivideo->warncount++ < 10)
1816                        printk(KERN_INFO
1817                                "sisfb: Deprecated ioctl call received - update your application!\n");
1818                /* fall through */
1819           case SISFB_SET_AUTOMAXIMIZE:
1820                if(get_user(gpu32, argp))
1821                        return -EFAULT;
1822
1823                ivideo->sisfb_max = (gpu32) ? 1 : 0;
1824                break;
1825
1826           case SISFB_SET_TVPOSOFFSET:
1827                if(get_user(gpu32, argp))
1828                        return -EFAULT;
1829
1830                sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1831                sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1832                break;
1833
1834           case SISFB_GET_TVPOSOFFSET:
1835                return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1836                                                        argp);
1837
1838           case SISFB_COMMAND:
1839                if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1840                                                        sizeof(struct sisfb_cmd)))
1841                        return -EFAULT;
1842
1843                sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1844
1845                if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1846                                                        sizeof(struct sisfb_cmd)))
1847                        return -EFAULT;
1848
1849                break;
1850
1851           case SISFB_SET_LOCK:
1852                if(get_user(gpu32, argp))
1853                        return -EFAULT;
1854
1855                ivideo->sisfblocked = (gpu32) ? 1 : 0;
1856                break;
1857
1858           default:
1859#ifdef SIS_NEW_CONFIG_COMPAT
1860                return -ENOIOCTLCMD;
1861#else
1862                return -EINVAL;
1863#endif
1864        }
1865        return 0;
1866}
1867
1868static int
1869sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1870{
1871        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1872
1873        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1874
1875        strlcpy(fix->id, ivideo->myid, sizeof(fix->id));
1876
1877        mutex_lock(&info->mm_lock);
1878        fix->smem_start  = ivideo->video_base + ivideo->video_offset;
1879        fix->smem_len    = ivideo->sisfb_mem;
1880        mutex_unlock(&info->mm_lock);
1881        fix->type        = FB_TYPE_PACKED_PIXELS;
1882        fix->type_aux    = 0;
1883        fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1884        fix->xpanstep    = 1;
1885        fix->ypanstep    = (ivideo->sisfb_ypan) ? 1 : 0;
1886        fix->ywrapstep   = 0;
1887        fix->line_length = ivideo->video_linelength;
1888        fix->mmio_start  = ivideo->mmio_base;
1889        fix->mmio_len    = ivideo->mmio_size;
1890        if(ivideo->sisvga_engine == SIS_300_VGA) {
1891                fix->accel = FB_ACCEL_SIS_GLAMOUR;
1892        } else if((ivideo->chip == SIS_330) ||
1893                  (ivideo->chip == SIS_760) ||
1894                  (ivideo->chip == SIS_761)) {
1895                fix->accel = FB_ACCEL_SIS_XABRE;
1896        } else if(ivideo->chip == XGI_20) {
1897                fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1898        } else if(ivideo->chip >= XGI_40) {
1899                fix->accel = FB_ACCEL_XGI_VOLARI_V;
1900        } else {
1901                fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1902        }
1903
1904        return 0;
1905}
1906
1907/* ----------------  fb_ops structures ----------------- */
1908
1909static struct fb_ops sisfb_ops = {
1910        .owner          = THIS_MODULE,
1911        .fb_open        = sisfb_open,
1912        .fb_release     = sisfb_release,
1913        .fb_check_var   = sisfb_check_var,
1914        .fb_set_par     = sisfb_set_par,
1915        .fb_setcolreg   = sisfb_setcolreg,
1916        .fb_pan_display = sisfb_pan_display,
1917        .fb_blank       = sisfb_blank,
1918        .fb_fillrect    = fbcon_sis_fillrect,
1919        .fb_copyarea    = fbcon_sis_copyarea,
1920        .fb_imageblit   = cfb_imageblit,
1921        .fb_sync        = fbcon_sis_sync,
1922#ifdef SIS_NEW_CONFIG_COMPAT
1923        .fb_compat_ioctl= sisfb_ioctl,
1924#endif
1925        .fb_ioctl       = sisfb_ioctl
1926};
1927
1928/* ---------------- Chip generation dependent routines ---------------- */
1929
1930static struct pci_dev *sisfb_get_northbridge(int basechipid)
1931{
1932        struct pci_dev *pdev = NULL;
1933        int nbridgenum, nbridgeidx, i;
1934        static const unsigned short nbridgeids[] = {
1935                PCI_DEVICE_ID_SI_540,   /* for SiS 540 VGA */
1936                PCI_DEVICE_ID_SI_630,   /* for SiS 630/730 VGA */
1937                PCI_DEVICE_ID_SI_730,
1938                PCI_DEVICE_ID_SI_550,   /* for SiS 550 VGA */
1939                PCI_DEVICE_ID_SI_650,   /* for SiS 650/651/740 VGA */
1940                PCI_DEVICE_ID_SI_651,
1941                PCI_DEVICE_ID_SI_740,
1942                PCI_DEVICE_ID_SI_661,   /* for SiS 661/741/660/760/761 VGA */
1943                PCI_DEVICE_ID_SI_741,
1944                PCI_DEVICE_ID_SI_660,
1945                PCI_DEVICE_ID_SI_760,
1946                PCI_DEVICE_ID_SI_761
1947        };
1948
1949        switch(basechipid) {
1950#ifdef CONFIG_FB_SIS_300
1951        case SIS_540:   nbridgeidx = 0; nbridgenum = 1; break;
1952        case SIS_630:   nbridgeidx = 1; nbridgenum = 2; break;
1953#endif
1954#ifdef CONFIG_FB_SIS_315
1955        case SIS_550:   nbridgeidx = 3; nbridgenum = 1; break;
1956        case SIS_650:   nbridgeidx = 4; nbridgenum = 3; break;
1957        case SIS_660:   nbridgeidx = 7; nbridgenum = 5; break;
1958#endif
1959        default:        return NULL;
1960        }
1961        for(i = 0; i < nbridgenum; i++) {
1962                if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
1963                                nbridgeids[nbridgeidx+i], NULL)))
1964                        break;
1965        }
1966        return pdev;
1967}
1968
1969static int sisfb_get_dram_size(struct sis_video_info *ivideo)
1970{
1971#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1972        u8 reg;
1973#endif
1974
1975        ivideo->video_size = 0;
1976        ivideo->UMAsize = ivideo->LFBsize = 0;
1977
1978        switch(ivideo->chip) {
1979#ifdef CONFIG_FB_SIS_300
1980        case SIS_300:
1981                reg = SiS_GetReg(SISSR, 0x14);
1982                ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1983                break;
1984        case SIS_540:
1985        case SIS_630:
1986        case SIS_730:
1987                if(!ivideo->nbridge)
1988                        return -1;
1989                pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
1990                ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1991                break;
1992#endif
1993#ifdef CONFIG_FB_SIS_315
1994        case SIS_315H:
1995        case SIS_315PRO:
1996        case SIS_315:
1997                reg = SiS_GetReg(SISSR, 0x14);
1998                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1999                switch((reg >> 2) & 0x03) {
2000                case 0x01:
2001                case 0x03:
2002                        ivideo->video_size <<= 1;
2003                        break;
2004                case 0x02:
2005                        ivideo->video_size += (ivideo->video_size/2);
2006                }
2007                break;
2008        case SIS_330:
2009                reg = SiS_GetReg(SISSR, 0x14);
2010                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2011                if(reg & 0x0c) ivideo->video_size <<= 1;
2012                break;
2013        case SIS_550:
2014        case SIS_650:
2015        case SIS_740:
2016                reg = SiS_GetReg(SISSR, 0x14);
2017                ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2018                break;
2019        case SIS_661:
2020        case SIS_741:
2021                reg = SiS_GetReg(SISCR, 0x79);
2022                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2023                break;
2024        case SIS_660:
2025        case SIS_760:
2026        case SIS_761:
2027                reg = SiS_GetReg(SISCR, 0x79);
2028                reg = (reg & 0xf0) >> 4;
2029                if(reg) {
2030                        ivideo->video_size = (1 << reg) << 20;
2031                        ivideo->UMAsize = ivideo->video_size;
2032                }
2033                reg = SiS_GetReg(SISCR, 0x78);
2034                reg &= 0x30;
2035                if(reg) {
2036                        if(reg == 0x10) {
2037                                ivideo->LFBsize = (32 << 20);
2038                        } else {
2039                                ivideo->LFBsize = (64 << 20);
2040                        }
2041                        ivideo->video_size += ivideo->LFBsize;
2042                }
2043                break;
2044        case SIS_340:
2045        case XGI_20:
2046        case XGI_40:
2047                reg = SiS_GetReg(SISSR, 0x14);
2048                ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2049                if(ivideo->chip != XGI_20) {
2050                        reg = (reg & 0x0c) >> 2;
2051                        if(ivideo->revision_id == 2) {
2052                                if(reg & 0x01) reg = 0x02;
2053                                else           reg = 0x00;
2054                        }
2055                        if(reg == 0x02)         ivideo->video_size <<= 1;
2056                        else if(reg == 0x03)    ivideo->video_size <<= 2;
2057                }
2058                break;
2059#endif
2060        default:
2061                return -1;
2062        }
2063        return 0;
2064}
2065
2066/* -------------- video bridge device detection --------------- */
2067
2068static void sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2069{
2070        u8 cr32, temp;
2071
2072        /* No CRT2 on XGI Z7 */
2073        if(ivideo->chip == XGI_20) {
2074                ivideo->sisfb_crt1off = 0;
2075                return;
2076        }
2077
2078#ifdef CONFIG_FB_SIS_300
2079        if(ivideo->sisvga_engine == SIS_300_VGA) {
2080                temp = SiS_GetReg(SISSR, 0x17);
2081                if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2082                        /* PAL/NTSC is stored on SR16 on such machines */
2083                        if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2084                                temp = SiS_GetReg(SISSR, 0x16);
2085                                if(temp & 0x20)
2086                                        ivideo->vbflags |= TV_PAL;
2087                                else
2088                                        ivideo->vbflags |= TV_NTSC;
2089                        }
2090                }
2091        }
2092#endif
2093
2094        cr32 = SiS_GetReg(SISCR, 0x32);
2095
2096        if(cr32 & SIS_CRT1) {
2097                ivideo->sisfb_crt1off = 0;
2098        } else {
2099                ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2100        }
2101
2102        ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2103
2104        if(cr32 & SIS_VB_TV)   ivideo->vbflags |= CRT2_TV;
2105        if(cr32 & SIS_VB_LCD)  ivideo->vbflags |= CRT2_LCD;
2106        if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2107
2108        /* Check given parms for hardware compatibility.
2109         * (Cannot do this in the search_xx routines since we don't
2110         * know what hardware we are running on then)
2111         */
2112
2113        if(ivideo->chip != SIS_550) {
2114           ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2115        }
2116
2117        if(ivideo->sisfb_tvplug != -1) {
2118           if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2119               (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2120              if(ivideo->sisfb_tvplug & TV_YPBPR) {
2121                 ivideo->sisfb_tvplug = -1;
2122                 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2123              }
2124           }
2125        }
2126        if(ivideo->sisfb_tvplug != -1) {
2127           if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2128               (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2129              if(ivideo->sisfb_tvplug & TV_HIVISION) {
2130                 ivideo->sisfb_tvplug = -1;
2131                 printk(KERN_ERR "sisfb: HiVision not supported\n");
2132              }
2133           }
2134        }
2135        if(ivideo->sisfb_tvstd != -1) {
2136           if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2137               (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2138                        (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2139              if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) {
2140                 ivideo->sisfb_tvstd = -1;
2141                 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2142              }
2143           }
2144        }
2145
2146        /* Detect/set TV plug & type */
2147        if(ivideo->sisfb_tvplug != -1) {
2148                ivideo->vbflags |= ivideo->sisfb_tvplug;
2149        } else {
2150                if(cr32 & SIS_VB_YPBPR)          ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2151                else if(cr32 & SIS_VB_HIVISION)  ivideo->vbflags |= TV_HIVISION;
2152                else if(cr32 & SIS_VB_SCART)     ivideo->vbflags |= TV_SCART;
2153                else {
2154                        if(cr32 & SIS_VB_SVIDEO)    ivideo->vbflags |= TV_SVIDEO;
2155                        if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2156                }
2157        }
2158
2159        if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2160            if(ivideo->sisfb_tvstd != -1) {
2161               ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2162               ivideo->vbflags |= ivideo->sisfb_tvstd;
2163            }
2164            if(ivideo->vbflags & TV_SCART) {
2165               ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2166               ivideo->vbflags |= TV_PAL;
2167            }
2168            if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2169                if(ivideo->sisvga_engine == SIS_300_VGA) {
2170                        temp = SiS_GetReg(SISSR, 0x38);
2171                        if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2172                        else            ivideo->vbflags |= TV_NTSC;
2173                } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2174                        temp = SiS_GetReg(SISSR, 0x38);
2175                        if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2176                        else            ivideo->vbflags |= TV_NTSC;
2177                } else {
2178                        temp = SiS_GetReg(SISCR, 0x79);
2179                        if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2180                        else            ivideo->vbflags |= TV_NTSC;
2181                }
2182            }
2183        }
2184
2185        /* Copy forceCRT1 option to CRT1off if option is given */
2186        if(ivideo->sisfb_forcecrt1 != -1) {
2187           ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2188        }
2189}
2190
2191/* ------------------ Sensing routines ------------------ */
2192
2193static bool sisfb_test_DDC1(struct sis_video_info *ivideo)
2194{
2195    unsigned short old;
2196    int count = 48;
2197
2198    old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2199    do {
2200        if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2201    } while(count--);
2202    return (count != -1);
2203}
2204
2205static void sisfb_sense_crt1(struct sis_video_info *ivideo)
2206{
2207    bool mustwait = false;
2208    u8  sr1F, cr17;
2209#ifdef CONFIG_FB_SIS_315
2210    u8  cr63=0;
2211#endif
2212    u16 temp = 0xffff;
2213    int i;
2214
2215    sr1F = SiS_GetReg(SISSR, 0x1F);
2216    SiS_SetRegOR(SISSR, 0x1F, 0x04);
2217    SiS_SetRegAND(SISSR, 0x1F, 0x3F);
2218    if(sr1F & 0xc0) mustwait = true;
2219
2220#ifdef CONFIG_FB_SIS_315
2221    if(ivideo->sisvga_engine == SIS_315_VGA) {
2222       cr63 = SiS_GetReg(SISCR, ivideo->SiS_Pr.SiS_MyCR63);
2223       cr63 &= 0x40;
2224       SiS_SetRegAND(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF);
2225    }
2226#endif
2227
2228    cr17 = SiS_GetReg(SISCR, 0x17);
2229    cr17 &= 0x80;
2230    if(!cr17) {
2231       SiS_SetRegOR(SISCR, 0x17, 0x80);
2232       mustwait = true;
2233       SiS_SetReg(SISSR, 0x00, 0x01);
2234       SiS_SetReg(SISSR, 0x00, 0x03);
2235    }
2236
2237    if(mustwait) {
2238       for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2239    }
2240
2241#ifdef CONFIG_FB_SIS_315
2242    if(ivideo->chip >= SIS_330) {
2243       SiS_SetRegAND(SISCR, 0x32, ~0x20);
2244       if(ivideo->chip >= SIS_340) {
2245           SiS_SetReg(SISCR, 0x57, 0x4a);
2246       } else {
2247           SiS_SetReg(SISCR, 0x57, 0x5f);
2248       }
2249        SiS_SetRegOR(SISCR, 0x53, 0x02);
2250        while ((SiS_GetRegByte(SISINPSTAT)) & 0x01)    break;
2251        while (!((SiS_GetRegByte(SISINPSTAT)) & 0x01)) break;
2252        if ((SiS_GetRegByte(SISMISCW)) & 0x10) temp = 1;
2253        SiS_SetRegAND(SISCR, 0x53, 0xfd);
2254        SiS_SetRegAND(SISCR, 0x57, 0x00);
2255    }
2256#endif
2257
2258    if(temp == 0xffff) {
2259       i = 3;
2260       do {
2261          temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2262                ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2263       } while(((temp == 0) || (temp == 0xffff)) && i--);
2264
2265       if((temp == 0) || (temp == 0xffff)) {
2266          if(sisfb_test_DDC1(ivideo)) temp = 1;
2267       }
2268    }
2269
2270    if((temp) && (temp != 0xffff)) {
2271       SiS_SetRegOR(SISCR, 0x32, 0x20);
2272    }
2273
2274#ifdef CONFIG_FB_SIS_315
2275    if(ivideo->sisvga_engine == SIS_315_VGA) {
2276        SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF, cr63);
2277    }
2278#endif
2279
2280    SiS_SetRegANDOR(SISCR, 0x17, 0x7F, cr17);
2281
2282    SiS_SetReg(SISSR, 0x1F, sr1F);
2283}
2284
2285/* Determine and detect attached devices on SiS30x */
2286static void SiS_SenseLCD(struct sis_video_info *ivideo)
2287{
2288        unsigned char buffer[256];
2289        unsigned short temp, realcrtno, i;
2290        u8 reg, cr37 = 0, paneltype = 0;
2291        u16 xres, yres;
2292
2293        ivideo->SiS_Pr.PanelSelfDetected = false;
2294
2295        /* LCD detection only for TMDS bridges */
2296        if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2297                return;
2298        if(ivideo->vbflags2 & VB2_30xBDH)
2299                return;
2300
2301        /* If LCD already set up by BIOS, skip it */
2302        reg = SiS_GetReg(SISCR, 0x32);
2303        if(reg & 0x08)
2304                return;
2305
2306        realcrtno = 1;
2307        if(ivideo->SiS_Pr.DDCPortMixup)
2308                realcrtno = 0;
2309
2310        /* Check DDC capabilities */
2311        temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2312                                realcrtno, 0, &buffer[0], ivideo->vbflags2);
2313
2314        if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2315                return;
2316
2317        /* Read DDC data */
2318        i = 3;  /* Number of retrys */
2319        do {
2320                temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2321                                ivideo->sisvga_engine, realcrtno, 1,
2322                                &buffer[0], ivideo->vbflags2);
2323        } while((temp) && i--);
2324
2325        if(temp)
2326                return;
2327
2328        /* No digital device */
2329        if(!(buffer[0x14] & 0x80))
2330                return;
2331
2332        /* First detailed timing preferred timing? */
2333        if(!(buffer[0x18] & 0x02))
2334                return;
2335
2336        xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2337        yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2338
2339        switch(xres) {
2340                case 1024:
2341                        if(yres == 768)
2342                                paneltype = 0x02;
2343                        break;
2344                case 1280:
2345                        if(yres == 1024)
2346                                paneltype = 0x03;
2347                        break;
2348                case 1600:
2349                        if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2350                                paneltype = 0x0b;
2351                        break;
2352        }
2353
2354        if(!paneltype)
2355                return;
2356
2357        if(buffer[0x23])
2358                cr37 |= 0x10;
2359
2360        if((buffer[0x47] & 0x18) == 0x18)
2361                cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2362        else
2363                cr37 |= 0xc0;
2364
2365        SiS_SetReg(SISCR, 0x36, paneltype);
2366        cr37 &= 0xf1;
2367        SiS_SetRegANDOR(SISCR, 0x37, 0x0c, cr37);
2368        SiS_SetRegOR(SISCR, 0x32, 0x08);
2369
2370        ivideo->SiS_Pr.PanelSelfDetected = true;
2371}
2372
2373static int SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2374{
2375    int temp, mytest, result, i, j;
2376
2377    for(j = 0; j < 10; j++) {
2378       result = 0;
2379       for(i = 0; i < 3; i++) {
2380          mytest = test;
2381           SiS_SetReg(SISPART4, 0x11, (type & 0x00ff));
2382          temp = (type >> 8) | (mytest & 0x00ff);
2383          SiS_SetRegANDOR(SISPART4, 0x10, 0xe0, temp);
2384          SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2385          mytest >>= 8;
2386          mytest &= 0x7f;
2387           temp = SiS_GetReg(SISPART4, 0x03);
2388          temp ^= 0x0e;
2389          temp &= mytest;
2390          if(temp == mytest) result++;
2391#if 1
2392          SiS_SetReg(SISPART4, 0x11, 0x00);
2393          SiS_SetRegAND(SISPART4, 0x10, 0xe0);
2394          SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2395#endif
2396       }
2397       if((result == 0) || (result >= 2)) break;
2398    }
2399    return result;
2400}
2401
2402static void SiS_Sense30x(struct sis_video_info *ivideo)
2403{
2404    u8  backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2405    u16 svhs=0, svhs_c=0;
2406    u16 cvbs=0, cvbs_c=0;
2407    u16 vga2=0, vga2_c=0;
2408    int myflag, result;
2409    char stdstr[] = "sisfb: Detected";
2410    char tvstr[]  = "TV connected to";
2411
2412    if(ivideo->vbflags2 & VB2_301) {
2413       svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2414       myflag = SiS_GetReg(SISPART4, 0x01);
2415       if(myflag & 0x04) {
2416          svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2417       }
2418    } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2419       svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2420    } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2421       svhs = 0x0200; cvbs = 0x0100;
2422    } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2423       svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2424    } else
2425       return;
2426
2427    vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2428    if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2429       svhs_c = 0x0408; cvbs_c = 0x0808;
2430    }
2431
2432    biosflag = 2;
2433    if(ivideo->haveXGIROM) {
2434       biosflag = ivideo->bios_abase[0x58] & 0x03;
2435    } else if(ivideo->newrom) {
2436       if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2437    } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2438       if(ivideo->bios_abase) {
2439          biosflag = ivideo->bios_abase[0xfe] & 0x03;
2440       }
2441    }
2442
2443    if(ivideo->chip == SIS_300) {
2444       myflag = SiS_GetReg(SISSR, 0x3b);
2445       if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2446    }
2447
2448    if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2449       vga2 = vga2_c = 0;
2450    }
2451
2452    backupSR_1e = SiS_GetReg(SISSR, 0x1e);
2453    SiS_SetRegOR(SISSR, 0x1e, 0x20);
2454
2455    backupP4_0d = SiS_GetReg(SISPART4, 0x0d);
2456    if(ivideo->vbflags2 & VB2_30xC) {
2457        SiS_SetRegANDOR(SISPART4, 0x0d, ~0x07, 0x01);
2458    } else {
2459       SiS_SetRegOR(SISPART4, 0x0d, 0x04);
2460    }
2461    SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2462
2463    backupP2_00 = SiS_GetReg(SISPART2, 0x00);
2464    SiS_SetReg(SISPART2, 0x00, ((backupP2_00 | 0x1c) & 0xfc));
2465
2466    backupP2_4d = SiS_GetReg(SISPART2, 0x4d);
2467    if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2468        SiS_SetReg(SISPART2, 0x4d, (backupP2_4d & ~0x10));
2469    }
2470
2471    if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2472       SISDoSense(ivideo, 0, 0);
2473    }
2474
2475    SiS_SetRegAND(SISCR, 0x32, ~0x14);
2476
2477    if(vga2_c || vga2) {
2478       if(SISDoSense(ivideo, vga2, vga2_c)) {
2479          if(biosflag & 0x01) {
2480             printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2481             SiS_SetRegOR(SISCR, 0x32, 0x04);
2482          } else {
2483             printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2484             SiS_SetRegOR(SISCR, 0x32, 0x10);
2485          }
2486       }
2487    }
2488
2489    SiS_SetRegAND(SISCR, 0x32, 0x3f);
2490
2491    if(ivideo->vbflags2 & VB2_30xCLV) {
2492       SiS_SetRegOR(SISPART4, 0x0d, 0x04);
2493    }
2494
2495    if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2496       SiS_SetReg(SISPART2, 0x4d, (backupP2_4d | 0x10));
2497       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2498       if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2499          if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2500             printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2501             SiS_SetRegOR(SISCR, 0x32, 0x80);
2502          }
2503       }
2504       SiS_SetReg(SISPART2, 0x4d, backupP2_4d);
2505    }
2506
2507    SiS_SetRegAND(SISCR, 0x32, ~0x03);
2508
2509    if(!(ivideo->vbflags & TV_YPBPR)) {
2510       if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2511          printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2512           SiS_SetRegOR(SISCR, 0x32, 0x02);
2513       }
2514       if((biosflag & 0x02) || (!result)) {
2515          if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2516             printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2517             SiS_SetRegOR(SISCR, 0x32, 0x01);
2518          }
2519       }
2520    }
2521
2522    SISDoSense(ivideo, 0, 0);
2523
2524    SiS_SetReg(SISPART2, 0x00, backupP2_00);
2525    SiS_SetReg(SISPART4, 0x0d, backupP4_0d);
2526    SiS_SetReg(SISSR, 0x1e, backupSR_1e);
2527
2528    if(ivideo->vbflags2 & VB2_30xCLV) {
2529        biosflag = SiS_GetReg(SISPART2, 0x00);
2530       if(biosflag & 0x20) {
2531          for(myflag = 2; myflag > 0; myflag--) {
2532             biosflag ^= 0x20;
2533             SiS_SetReg(SISPART2, 0x00, biosflag);
2534          }
2535       }
2536    }
2537
2538    SiS_SetReg(SISPART2, 0x00, backupP2_00);
2539}
2540
2541/* Determine and detect attached TV's on Chrontel */
2542static void SiS_SenseCh(struct sis_video_info *ivideo)
2543{
2544#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2545    u8 temp1, temp2;
2546    char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2547#endif
2548#ifdef CONFIG_FB_SIS_300
2549    unsigned char test[3];
2550    int i;
2551#endif
2552
2553    if(ivideo->chip < SIS_315H) {
2554
2555#ifdef CONFIG_FB_SIS_300
2556       ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1;            /* Chrontel 700x */
2557       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c);      /* Set general purpose IO for Chrontel communication */
2558       SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2559       temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2560       /* See Chrontel TB31 for explanation */
2561       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2562       if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2563          SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2564          SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2565       }
2566       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2567       if(temp2 != temp1) temp1 = temp2;
2568
2569       if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2570           /* Read power status */
2571           temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2572           if((temp1 & 0x03) != 0x03) {
2573                /* Power all outputs */
2574                SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2575                SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2576           }
2577           /* Sense connected TV devices */
2578           for(i = 0; i < 3; i++) {
2579               SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2580               SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2581               SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2582               SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2583               temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2584               if(!(temp1 & 0x08))       test[i] = 0x02;
2585               else if(!(temp1 & 0x02))  test[i] = 0x01;
2586               else                      test[i] = 0;
2587               SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2588           }
2589
2590           if(test[0] == test[1])      temp1 = test[0];
2591           else if(test[0] == test[2]) temp1 = test[0];
2592           else if(test[1] == test[2]) temp1 = test[1];
2593           else {
2594                printk(KERN_INFO
2595                        "sisfb: TV detection unreliable - test results varied\n");
2596                temp1 = test[2];
2597           }
2598           if(temp1 == 0x02) {
2599                printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2600                ivideo->vbflags |= TV_SVIDEO;
2601                SiS_SetRegOR(SISCR, 0x32, 0x02);
2602                SiS_SetRegAND(SISCR, 0x32, ~0x05);
2603           } else if (temp1 == 0x01) {
2604                printk(KERN_INFO "%s CVBS output\n", stdstr);
2605                ivideo->vbflags |= TV_AVIDEO;
2606                SiS_SetRegOR(SISCR, 0x32, 0x01);
2607                SiS_SetRegAND(SISCR, 0x32, ~0x06);
2608           } else {
2609                SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2610                SiS_SetRegAND(SISCR, 0x32, ~0x07);
2611           }
2612       } else if(temp1 == 0) {
2613          SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2614          SiS_SetRegAND(SISCR, 0x32, ~0x07);
2615       }
2616       /* Set general purpose IO for Chrontel communication */
2617       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2618#endif
2619
2620    } else {
2621
2622#ifdef CONFIG_FB_SIS_315
2623        ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2;           /* Chrontel 7019 */
2624        temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2625        SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2626        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2627        temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2628        temp2 |= 0x01;
2629        SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2630        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2631        temp2 ^= 0x01;
2632        SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2633        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2634        temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2635        SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2636        temp1 = 0;
2637        if(temp2 & 0x02) temp1 |= 0x01;
2638        if(temp2 & 0x10) temp1 |= 0x01;
2639        if(temp2 & 0x04) temp1 |= 0x02;
2640        if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2641        switch(temp1) {
2642        case 0x01:
2643             printk(KERN_INFO "%s CVBS output\n", stdstr);
2644             ivideo->vbflags |= TV_AVIDEO;
2645             SiS_SetRegOR(SISCR, 0x32, 0x01);
2646             SiS_SetRegAND(SISCR, 0x32, ~0x06);
2647             break;
2648        case 0x02:
2649             printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2650             ivideo->vbflags |= TV_SVIDEO;
2651             SiS_SetRegOR(SISCR, 0x32, 0x02);
2652             SiS_SetRegAND(SISCR, 0x32, ~0x05);
2653             break;
2654        case 0x04:
2655             printk(KERN_INFO "%s SCART output\n", stdstr);
2656             SiS_SetRegOR(SISCR, 0x32, 0x04);
2657             SiS_SetRegAND(SISCR, 0x32, ~0x03);
2658             break;
2659        default:
2660             SiS_SetRegAND(SISCR, 0x32, ~0x07);
2661        }
2662#endif
2663    }
2664}
2665
2666static void sisfb_get_VB_type(struct sis_video_info *ivideo)
2667{
2668        char stdstr[]    = "sisfb: Detected";
2669        char bridgestr[] = "video bridge";
2670        u8 vb_chipid;
2671        u8 reg;
2672
2673        /* No CRT2 on XGI Z7 */
2674        if(ivideo->chip == XGI_20)
2675                return;
2676
2677        vb_chipid = SiS_GetReg(SISPART4, 0x00);
2678        switch(vb_chipid) {
2679        case 0x01:
2680                reg = SiS_GetReg(SISPART4, 0x01);
2681                if(reg < 0xb0) {
2682                        ivideo->vbflags |= VB_301;      /* Deprecated */
2683                        ivideo->vbflags2 |= VB2_301;
2684                        printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2685                } else if(reg < 0xc0) {
2686                        ivideo->vbflags |= VB_301B;     /* Deprecated */
2687                        ivideo->vbflags2 |= VB2_301B;
2688                        reg = SiS_GetReg(SISPART4, 0x23);
2689                        if(!(reg & 0x02)) {
2690                           ivideo->vbflags |= VB_30xBDH;        /* Deprecated */
2691                           ivideo->vbflags2 |= VB2_30xBDH;
2692                           printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2693                        } else {
2694                           printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2695                        }
2696                } else if(reg < 0xd0) {
2697                        ivideo->vbflags |= VB_301C;     /* Deprecated */
2698                        ivideo->vbflags2 |= VB2_301C;
2699                        printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2700                } else if(reg < 0xe0) {
2701                        ivideo->vbflags |= VB_301LV;    /* Deprecated */
2702                        ivideo->vbflags2 |= VB2_301LV;
2703                        printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2704                } else if(reg <= 0xe1) {
2705                        reg = SiS_GetReg(SISPART4, 0x39);
2706                        if(reg == 0xff) {
2707                           ivideo->vbflags |= VB_302LV; /* Deprecated */
2708                           ivideo->vbflags2 |= VB2_302LV;
2709                           printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2710                        } else {
2711                           ivideo->vbflags |= VB_301C;  /* Deprecated */
2712                           ivideo->vbflags2 |= VB2_301C;
2713                           printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2714#if 0
2715                           ivideo->vbflags |= VB_302ELV;        /* Deprecated */
2716                           ivideo->vbflags2 |= VB2_302ELV;
2717                           printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2718#endif
2719                        }
2720                }
2721                break;
2722        case 0x02:
2723                ivideo->vbflags |= VB_302B;     /* Deprecated */
2724                ivideo->vbflags2 |= VB2_302B;
2725                printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2726                break;
2727        }
2728
2729        if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2730                reg = SiS_GetReg(SISCR, 0x37);
2731                reg &= SIS_EXTERNAL_CHIP_MASK;
2732                reg >>= 1;
2733                if(ivideo->sisvga_engine == SIS_300_VGA) {
2734#ifdef CONFIG_FB_SIS_300
2735                        switch(reg) {
2736                           case SIS_EXTERNAL_CHIP_LVDS:
2737                                ivideo->vbflags |= VB_LVDS;     /* Deprecated */
2738                                ivideo->vbflags2 |= VB2_LVDS;
2739                                break;
2740                           case SIS_EXTERNAL_CHIP_TRUMPION:
2741                                ivideo->vbflags |= (VB_LVDS | VB_TRUMPION);     /* Deprecated */
2742                                ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2743                                break;
2744                           case SIS_EXTERNAL_CHIP_CHRONTEL:
2745                                ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2746                                ivideo->vbflags2 |= VB2_CHRONTEL;
2747                                break;
2748                           case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2749                                ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
2750                                ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2751                                break;
2752                        }
2753                        if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2754#endif
2755                } else if(ivideo->chip < SIS_661) {
2756#ifdef CONFIG_FB_SIS_315
2757                        switch (reg) {
2758                           case SIS310_EXTERNAL_CHIP_LVDS:
2759                                ivideo->vbflags |= VB_LVDS;     /* Deprecated */
2760                                ivideo->vbflags2 |= VB2_LVDS;
2761                                break;
2762                           case SIS310_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 = 2;
2768#endif
2769                } else if(ivideo->chip >= SIS_661) {
2770#ifdef CONFIG_FB_SIS_315
2771                        reg = SiS_GetReg(SISCR, 0x38);
2772                        reg >>= 5;
2773                        switch(reg) {
2774                           case 0x02:
2775                                ivideo->vbflags |= VB_LVDS;     /* Deprecated */
2776                                ivideo->vbflags2 |= VB2_LVDS;
2777                                break;
2778                           case 0x03:
2779                                ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
2780                                ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2781                                break;
2782                           case 0x04:
2783                                ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);     /* Deprecated */
2784                                ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2785                                break;
2786                        }
2787                        if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2788#endif
2789                }
2790                if(ivideo->vbflags2 & VB2_LVDS) {
2791                   printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2792                }
2793                if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2794                   printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2795                }
2796                if(ivideo->vbflags2 & VB2_CHRONTEL) {
2797                   printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2798                }
2799                if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2800                   printk(KERN_INFO "%s Conexant external device\n", stdstr);
2801                }
2802        }
2803
2804        if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2805                SiS_SenseLCD(ivideo);
2806                SiS_Sense30x(ivideo);
2807        } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2808                SiS_SenseCh(ivideo);
2809        }
2810}
2811
2812/* ---------- Engine initialization routines ------------ */
2813
2814static void
2815sisfb_engine_init(struct sis_video_info *ivideo)
2816{
2817
2818        /* Initialize command queue (we use MMIO only) */
2819
2820        /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2821
2822        ivideo->caps &= ~(TURBO_QUEUE_CAP    |
2823                          MMIO_CMD_QUEUE_CAP |
2824                          VM_CMD_QUEUE_CAP   |
2825                          AGP_CMD_QUEUE_CAP);
2826
2827#ifdef CONFIG_FB_SIS_300
2828        if(ivideo->sisvga_engine == SIS_300_VGA) {
2829                u32 tqueue_pos;
2830                u8 tq_state;
2831
2832                tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2833
2834                tq_state = SiS_GetReg(SISSR, IND_SIS_TURBOQUEUE_SET);
2835                tq_state |= 0xf0;
2836                tq_state &= 0xfc;
2837                tq_state |= (u8)(tqueue_pos >> 8);
2838                SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2839
2840                SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2841
2842                ivideo->caps |= TURBO_QUEUE_CAP;
2843        }
2844#endif
2845
2846#ifdef CONFIG_FB_SIS_315
2847        if(ivideo->sisvga_engine == SIS_315_VGA) {
2848                u32 tempq = 0, templ;
2849                u8  temp;
2850
2851                if(ivideo->chip == XGI_20) {
2852                        switch(ivideo->cmdQueueSize) {
2853                        case (64 * 1024):
2854                                temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2855                                break;
2856                        case (128 * 1024):
2857                        default:
2858                                temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2859                        }
2860                } else {
2861                        switch(ivideo->cmdQueueSize) {
2862                        case (4 * 1024 * 1024):
2863                                temp = SIS_CMD_QUEUE_SIZE_4M;
2864                                break;
2865                        case (2 * 1024 * 1024):
2866                                temp = SIS_CMD_QUEUE_SIZE_2M;
2867                                break;
2868                        case (1 * 1024 * 1024):
2869                                temp = SIS_CMD_QUEUE_SIZE_1M;
2870                                break;
2871                        default:
2872                        case (512 * 1024):
2873                                temp = SIS_CMD_QUEUE_SIZE_512k;
2874                        }
2875                }
2876
2877                SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2878                SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2879
2880                if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2881                        /* Must disable dual pipe on XGI_40. Can't do
2882                         * this in MMIO mode, because it requires
2883                         * setting/clearing a bit in the MMIO fire trigger
2884                         * register.
2885                         */
2886                        if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2887
2888                                MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2889
2890                                SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2891
2892                                tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2893                                MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2894
2895                                tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2896                                MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2897
2898                                writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2899                                writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2900                                writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2901                                writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2902
2903                                MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2904
2905                                sisfb_syncaccel(ivideo);
2906
2907                                SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2908
2909                        }
2910                }
2911
2912                tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2913                MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2914
2915                temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2916                SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2917
2918                tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2919                MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2920
2921                ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2922        }
2923#endif
2924
2925        ivideo->engineok = 1;
2926}
2927
2928static void sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2929{
2930        u8 reg;
2931        int i;
2932
2933        reg = SiS_GetReg(SISCR, 0x36);
2934        reg &= 0x0f;
2935        if(ivideo->sisvga_engine == SIS_300_VGA) {
2936                ivideo->CRT2LCDType = sis300paneltype[reg];
2937        } else if(ivideo->chip >= SIS_661) {
2938                ivideo->CRT2LCDType = sis661paneltype[reg];
2939        } else {
2940                ivideo->CRT2LCDType = sis310paneltype[reg];
2941                if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2942                        if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2943                           (ivideo->CRT2LCDType != LCD_320x240_3)) {
2944                                ivideo->CRT2LCDType = LCD_320x240;
2945                        }
2946                }
2947        }
2948
2949        if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2950                /* For broken BIOSes: Assume 1024x768, RGB18 */
2951                ivideo->CRT2LCDType = LCD_1024x768;
2952                SiS_SetRegANDOR(SISCR, 0x36, 0xf0, 0x02);
2953                SiS_SetRegANDOR(SISCR, 0x37, 0xee, 0x01);
2954                printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2955        }
2956
2957        for(i = 0; i < SIS_LCD_NUMBER; i++) {
2958                if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2959                        ivideo->lcdxres = sis_lcd_data[i].xres;
2960                        ivideo->lcdyres = sis_lcd_data[i].yres;
2961                        ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2962                        break;
2963                }
2964        }
2965
2966#ifdef CONFIG_FB_SIS_300
2967        if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2968                ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2969                ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2970        } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2971                ivideo->lcdxres =  848; ivideo->lcdyres =  480;
2972                ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2973        } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2974                ivideo->lcdxres =  856; ivideo->lcdyres =  480;
2975                ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2976        }
2977#endif
2978
2979        printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2980                        ivideo->lcdxres, ivideo->lcdyres);
2981}
2982
2983static void sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2984{
2985#ifdef CONFIG_FB_SIS_300
2986        /* Save the current PanelDelayCompensation if the LCD is currently used */
2987        if(ivideo->sisvga_engine == SIS_300_VGA) {
2988                if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2989                        int tmp;
2990                        tmp = SiS_GetReg(SISCR, 0x30);
2991                        if(tmp & 0x20) {
2992                                /* Currently on LCD? If yes, read current pdc */
2993                                ivideo->detectedpdc = SiS_GetReg(SISPART1, 0x13);
2994                                ivideo->detectedpdc &= 0x3c;
2995                                if(ivideo->SiS_Pr.PDC == -1) {
2996                                        /* Let option override detection */
2997                                        ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2998                                }
2999                                printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3000                                        ivideo->detectedpdc);
3001                        }
3002                        if((ivideo->SiS_Pr.PDC != -1) &&
3003                           (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3004                                printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3005                                        ivideo->SiS_Pr.PDC);
3006                        }
3007                }
3008        }
3009#endif
3010
3011#ifdef CONFIG_FB_SIS_315
3012        if(ivideo->sisvga_engine == SIS_315_VGA) {
3013
3014                /* Try to find about LCDA */
3015                if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3016                        int tmp;
3017                        tmp = SiS_GetReg(SISPART1, 0x13);
3018                        if(tmp & 0x04) {
3019                                ivideo->SiS_Pr.SiS_UseLCDA = true;
3020                                ivideo->detectedlcda = 0x03;
3021                        }
3022                }
3023
3024                /* Save PDC */
3025                if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3026                        int tmp;
3027                        tmp = SiS_GetReg(SISCR, 0x30);
3028                        if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3029                                /* Currently on LCD? If yes, read current pdc */
3030                                u8 pdc;
3031                                pdc = SiS_GetReg(SISPART1, 0x2D);
3032                                ivideo->detectedpdc  = (pdc & 0x0f) << 1;
3033                                ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3034                                pdc = SiS_GetReg(SISPART1, 0x35);
3035                                ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3036                                pdc = SiS_GetReg(SISPART1, 0x20);
3037                                ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3038                                if(ivideo->newrom) {
3039                                        /* New ROM invalidates other PDC resp. */
3040                                        if(ivideo->detectedlcda != 0xff) {
3041                                                ivideo->detectedpdc = 0xff;
3042                                        } else {
3043                                                ivideo->detectedpdca = 0xff;
3044                                        }
3045                                }
3046                                if(ivideo->SiS_Pr.PDC == -1) {
3047                                        if(ivideo->detectedpdc != 0xff) {
3048                                                ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3049                                        }
3050                                }
3051                                if(ivideo->SiS_Pr.PDCA == -1) {
3052                                        if(ivideo->detectedpdca != 0xff) {
3053                                                ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3054                                        }
3055                                }
3056                                if(ivideo->detectedpdc != 0xff) {
3057                                        printk(KERN_INFO
3058                                                "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3059                                                ivideo->detectedpdc);
3060                                }
3061                                if(ivideo->detectedpdca != 0xff) {
3062                                        printk(KERN_INFO
3063                                                "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3064                                                ivideo->detectedpdca);
3065                                }
3066                        }
3067
3068                        /* Save EMI */
3069                        if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3070                                ivideo->SiS_Pr.EMI_30 = SiS_GetReg(SISPART4, 0x30);
3071                                ivideo->SiS_Pr.EMI_31 = SiS_GetReg(SISPART4, 0x31);
3072                                ivideo->SiS_Pr.EMI_32 = SiS_GetReg(SISPART4, 0x32);
3073                                ivideo->SiS_Pr.EMI_33 = SiS_GetReg(SISPART4, 0x33);
3074                                ivideo->SiS_Pr.HaveEMI = true;
3075                                if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3076                                        ivideo->SiS_Pr.HaveEMILCD = true;
3077                                }
3078                        }
3079                }
3080
3081                /* Let user override detected PDCs (all bridges) */
3082                if(ivideo->vbflags2 & VB2_30xBLV) {
3083                        if((ivideo->SiS_Pr.PDC != -1) &&
3084                           (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3085                                printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3086                                        ivideo->SiS_Pr.PDC);
3087                        }
3088                        if((ivideo->SiS_Pr.PDCA != -1) &&
3089                           (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3090                                printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3091                                 ivideo->SiS_Pr.PDCA);
3092                        }
3093                }
3094
3095        }
3096#endif
3097}
3098
3099/* -------------------- Memory manager routines ---------------------- */
3100
3101static u32 sisfb_getheapstart(struct sis_video_info *ivideo)
3102{
3103        u32 ret = ivideo->sisfb_parm_mem * 1024;
3104        u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3105        u32 def;
3106
3107        /* Calculate heap start = end of memory for console
3108         *
3109         * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3110         * C = console, D = heap, H = HWCursor, Q = cmd-queue
3111         *
3112         * On 76x in UMA+LFB mode, the layout is as follows:
3113         * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3114         * where the heap is the entire UMA area, eventually
3115         * into the LFB area if the given mem parameter is
3116         * higher than the size of the UMA memory.
3117         *
3118         * Basically given by "mem" parameter
3119         *
3120         * maximum = videosize - cmd_queue - hwcursor
3121         *           (results in a heap of size 0)
3122         * default = SiS 300: depends on videosize
3123         *           SiS 315/330/340/XGI: 32k below max
3124         */
3125
3126        if(ivideo->sisvga_engine == SIS_300_VGA) {
3127                if(ivideo->video_size > 0x1000000) {
3128                        def = 0xc00000;
3129                } else if(ivideo->video_size > 0x800000) {
3130                        def = 0x800000;
3131                } else {
3132                        def = 0x400000;
3133                }
3134        } else if(ivideo->UMAsize && ivideo->LFBsize) {
3135                ret = def = 0;
3136        } else {
3137                def = maxoffs - 0x8000;
3138        }
3139
3140        /* Use default for secondary card for now (FIXME) */
3141        if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3142                ret = def;
3143
3144        return ret;
3145}
3146
3147static u32 sisfb_getheapsize(struct sis_video_info *ivideo)
3148{
3149        u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3150        u32 ret = 0;
3151
3152        if(ivideo->UMAsize && ivideo->LFBsize) {
3153                if( (!ivideo->sisfb_parm_mem)                   ||
3154                    ((ivideo->sisfb_parm_mem * 1024) > max)     ||
3155                    ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3156                        ret = ivideo->UMAsize;
3157                        max -= ivideo->UMAsize;
3158                } else {
3159                        ret = max - (ivideo->sisfb_parm_mem * 1024);
3160                        max = ivideo->sisfb_parm_mem * 1024;
3161                }
3162                ivideo->video_offset = ret;
3163                ivideo->sisfb_mem = max;
3164        } else {
3165                ret = max - ivideo->heapstart;
3166                ivideo->sisfb_mem = ivideo->heapstart;
3167        }
3168
3169        return ret;
3170}
3171
3172static int sisfb_heap_init(struct sis_video_info *ivideo)
3173{
3174        struct SIS_OH *poh;
3175
3176        ivideo->video_offset = 0;
3177        if(ivideo->sisfb_parm_mem) {
3178                if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3179                    (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3180                        ivideo->sisfb_parm_mem = 0;
3181                }
3182        }
3183
3184        ivideo->heapstart = sisfb_getheapstart(ivideo);
3185        ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3186
3187        ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3188        ivideo->sisfb_heap_end   = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3189
3190        printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3191                (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3192
3193        ivideo->sisfb_heap.vinfo = ivideo;
3194
3195        ivideo->sisfb_heap.poha_chain = NULL;
3196        ivideo->sisfb_heap.poh_freelist = NULL;
3197
3198        poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3199        if(poh == NULL)
3200                return 1;
3201
3202        poh->poh_next = &ivideo->sisfb_heap.oh_free;
3203        poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3204        poh->size = ivideo->sisfb_heap_size;
3205        poh->offset = ivideo->heapstart;
3206
3207        ivideo->sisfb_heap.oh_free.poh_next = poh;
3208        ivideo->sisfb_heap.oh_free.poh_prev = poh;
3209        ivideo->sisfb_heap.oh_free.size = 0;
3210        ivideo->sisfb_heap.max_freesize = poh->size;
3211
3212        ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3213        ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3214        ivideo->sisfb_heap.oh_used.size = SENTINEL;
3215
3216        if(ivideo->cardnumber == 0) {
3217                /* For the first card, make this heap the "global" one
3218                 * for old DRM (which could handle only one card)
3219                 */
3220                sisfb_heap = &ivideo->sisfb_heap;
3221        }
3222
3223        return 0;
3224}
3225
3226static struct SIS_OH *
3227sisfb_poh_new_node(struct SIS_HEAP *memheap)
3228{
3229        struct SIS_OHALLOC      *poha;
3230        struct SIS_OH           *poh;
3231        unsigned long           cOhs;
3232        int                     i;
3233
3234        if(memheap->poh_freelist == NULL) {
3235                poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3236                if(!poha)
3237                        return NULL;
3238
3239                poha->poha_next = memheap->poha_chain;
3240                memheap->poha_chain = poha;
3241
3242                cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3243
3244                poh = &poha->aoh[0];
3245                for(i = cOhs - 1; i != 0; i--) {
3246                        poh->poh_next = poh + 1;
3247                        poh = poh + 1;
3248                }
3249
3250                poh->poh_next = NULL;
3251                memheap->poh_freelist = &poha->aoh[0];
3252        }
3253
3254        poh = memheap->poh_freelist;
3255        memheap->poh_freelist = poh->poh_next;
3256
3257        return poh;
3258}
3259
3260static struct SIS_OH *
3261sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3262{
3263        struct SIS_OH   *pohThis;
3264        struct SIS_OH   *pohRoot;
3265        int             bAllocated = 0;
3266
3267        if(size > memheap->max_freesize) {
3268                DPRINTK("sisfb: Can't allocate %dk video memory\n",
3269                        (unsigned int) size / 1024);
3270                return NULL;
3271        }
3272
3273        pohThis = memheap->oh_free.poh_next;
3274
3275        while(pohThis != &memheap->oh_free) {
3276                if(size <= pohThis->size) {
3277                        bAllocated = 1;
3278                        break;
3279                }
3280                pohThis = pohThis->poh_next;
3281        }
3282
3283        if(!bAllocated) {
3284                DPRINTK("sisfb: Can't allocate %dk video memory\n",
3285                        (unsigned int) size / 1024);
3286                return NULL;
3287        }
3288
3289        if(size == pohThis->size) {
3290                pohRoot = pohThis;
3291                sisfb_delete_node(pohThis);
3292        } else {
3293                pohRoot = sisfb_poh_new_node(memheap);
3294                if(pohRoot == NULL)
3295                        return NULL;
3296
3297                pohRoot->offset = pohThis->offset;
3298                pohRoot->size = size;
3299
3300                pohThis->offset += size;
3301                pohThis->size -= size;
3302        }
3303
3304        memheap->max_freesize -= size;
3305
3306        pohThis = &memheap->oh_used;
3307        sisfb_insert_node(pohThis, pohRoot);
3308
3309        return pohRoot;
3310}
3311
3312static void
3313sisfb_delete_node(struct SIS_OH *poh)
3314{
3315        poh->poh_prev->poh_next = poh->poh_next;
3316        poh->poh_next->poh_prev = poh->poh_prev;
3317}
3318
3319static void
3320sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3321{
3322        struct SIS_OH *pohTemp = pohList->poh_next;
3323
3324        pohList->poh_next = poh;
3325        pohTemp->poh_prev = poh;
3326
3327        poh->poh_prev = pohList;
3328        poh->poh_next = pohTemp;
3329}
3330
3331static struct SIS_OH *
3332sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3333{
3334        struct SIS_OH *pohThis;
3335        struct SIS_OH *poh_freed;
3336        struct SIS_OH *poh_prev;
3337        struct SIS_OH *poh_next;
3338        u32    ulUpper;
3339        u32    ulLower;
3340        int    foundNode = 0;
3341
3342        poh_freed = memheap->oh_used.poh_next;
3343
3344        while(poh_freed != &memheap->oh_used) {
3345                if(poh_freed->offset == base) {
3346                        foundNode = 1;
3347                        break;
3348                }
3349
3350                poh_freed = poh_freed->poh_next;
3351        }
3352
3353        if(!foundNode)
3354                return NULL;
3355
3356        memheap->max_freesize += poh_freed->size;
3357
3358        poh_prev = poh_next = NULL;
3359        ulUpper = poh_freed->offset + poh_freed->size;
3360        ulLower = poh_freed->offset;
3361
3362        pohThis = memheap->oh_free.poh_next;
3363
3364        while(pohThis != &memheap->oh_free) {
3365                if(pohThis->offset == ulUpper) {
3366                        poh_next = pohThis;
3367                } else if((pohThis->offset + pohThis->size) == ulLower) {
3368                        poh_prev = pohThis;
3369                }
3370                pohThis = pohThis->poh_next;
3371        }
3372
3373        sisfb_delete_node(poh_freed);
3374
3375        if(poh_prev && poh_next) {
3376                poh_prev->size += (poh_freed->size + poh_next->size);
3377                sisfb_delete_node(poh_next);
3378                sisfb_free_node(memheap, poh_freed);
3379                sisfb_free_node(memheap, poh_next);
3380                return poh_prev;
3381        }
3382
3383        if(poh_prev) {
3384                poh_prev->size += poh_freed->size;
3385                sisfb_free_node(memheap, poh_freed);
3386                return poh_prev;
3387        }
3388
3389        if(poh_next) {
3390                poh_next->size += poh_freed->size;
3391                poh_next->offset = poh_freed->offset;
3392                sisfb_free_node(memheap, poh_freed);
3393                return poh_next;
3394        }
3395
3396        sisfb_insert_node(&memheap->oh_free, poh_freed);
3397
3398        return poh_freed;
3399}
3400
3401static void
3402sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3403{
3404        if(poh == NULL)
3405                return;
3406
3407        poh->poh_next = memheap->poh_freelist;
3408        memheap->poh_freelist = poh;
3409}
3410
3411static void
3412sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3413{
3414        struct SIS_OH *poh = NULL;
3415
3416        if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3417                poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3418
3419        if(poh == NULL) {
3420                req->offset = req->size = 0;
3421                DPRINTK("sisfb: Video RAM allocation failed\n");
3422        } else {
3423                req->offset = poh->offset;
3424                req->size = poh->size;
3425                DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3426                        (poh->offset + ivideo->video_vbase));
3427        }
3428}
3429
3430void
3431sis_malloc(struct sis_memreq *req)
3432{
3433        struct sis_video_info *ivideo = sisfb_heap->vinfo;
3434
3435        if(&ivideo->sisfb_heap == sisfb_heap)
3436                sis_int_malloc(ivideo, req);
3437        else
3438                req->offset = req->size = 0;
3439}
3440
3441void
3442sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3443{
3444        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3445
3446        sis_int_malloc(ivideo, req);
3447}
3448
3449/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3450
3451static void
3452sis_int_free(struct sis_video_info *ivideo, u32 base)
3453{
3454        struct SIS_OH *poh;
3455
3456        if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3457                return;
3458
3459        poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3460
3461        if(poh == NULL) {
3462                DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3463                        (unsigned int) base);
3464        }
3465}
3466
3467void
3468sis_free(u32 base)
3469{
3470        struct sis_video_info *ivideo = sisfb_heap->vinfo;
3471
3472        sis_int_free(ivideo, base);
3473}
3474
3475void
3476sis_free_new(struct pci_dev *pdev, u32 base)
3477{
3478        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3479
3480        sis_int_free(ivideo, base);
3481}
3482
3483/* --------------------- SetMode routines ------------------------- */
3484
3485static void
3486sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3487{
3488        u8 cr30, cr31;
3489
3490        /* Check if MMIO and engines are enabled,
3491         * and sync in case they are. Can't use
3492         * ivideo->accel here, as this might have
3493         * been changed before this is called.
3494         */
3495        cr30 = SiS_GetReg(SISSR, IND_SIS_PCI_ADDRESS_SET);
3496        cr31 = SiS_GetReg(SISSR, IND_SIS_MODULE_ENABLE);
3497        /* MMIO and 2D/3D engine enabled? */
3498        if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3499#ifdef CONFIG_FB_SIS_300
3500                if(ivideo->sisvga_engine == SIS_300_VGA) {
3501                        /* Don't care about TurboQueue. It's
3502                         * enough to know that the engines
3503                         * are enabled
3504                         */
3505                        sisfb_syncaccel(ivideo);
3506                }
3507#endif
3508#ifdef CONFIG_FB_SIS_315
3509                if(ivideo->sisvga_engine == SIS_315_VGA) {
3510                        /* Check that any queue mode is
3511                         * enabled, and that the queue
3512                         * is not in the state of "reset"
3513                         */
3514                        cr30 = SiS_GetReg(SISSR, 0x26);
3515                        if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3516                                sisfb_syncaccel(ivideo);
3517                        }
3518                }
3519#endif
3520        }
3521}
3522
3523static void
3524sisfb_pre_setmode(struct sis_video_info *ivideo)
3525{
3526        u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3527        int tvregnum = 0;
3528
3529        ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3530
3531        SiS_SetReg(SISSR, 0x05, 0x86);
3532
3533        cr31 = SiS_GetReg(SISCR, 0x31);
3534        cr31 &= ~0x60;
3535        cr31 |= 0x04;
3536
3537        cr33 = ivideo->rate_idx & 0x0F;
3538
3539#ifdef CONFIG_FB_SIS_315
3540        if(ivideo->sisvga_engine == SIS_315_VGA) {
3541           if(ivideo->chip >= SIS_661) {
3542              cr38 = SiS_GetReg(SISCR, 0x38);
3543              cr38 &= ~0x07;  /* Clear LCDA/DualEdge and YPbPr bits */
3544           } else {
3545              tvregnum = 0x38;
3546              cr38 = SiS_GetReg(SISCR, tvregnum);
3547              cr38 &= ~0x3b;  /* Clear LCDA/DualEdge and YPbPr bits */
3548           }
3549        }
3550#endif
3551#ifdef CONFIG_FB_SIS_300
3552        if(ivideo->sisvga_engine == SIS_300_VGA) {
3553           tvregnum = 0x35;
3554           cr38 = SiS_GetReg(SISCR, tvregnum);
3555        }
3556#endif
3557
3558        SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3559        SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
3560        ivideo->curFSTN = ivideo->curDSTN = 0;
3561
3562        switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3563
3564           case CRT2_TV:
3565              cr38 &= ~0xc0;   /* Clear PAL-M / PAL-N bits */
3566              if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3567#ifdef CONFIG_FB_SIS_315
3568                 if(ivideo->chip >= SIS_661) {
3569                    cr38 |= 0x04;
3570                    if(ivideo->vbflags & TV_YPBPR525P)       cr35 |= 0x20;
3571                    else if(ivideo->vbflags & TV_YPBPR750P)  cr35 |= 0x40;
3572                    else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3573                    cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3574                    cr35 &= ~0x01;
3575                    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3576                 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3577                    cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3578                    cr38 |= 0x08;
3579                    if(ivideo->vbflags & TV_YPBPR525P)       cr38 |= 0x10;
3580                    else if(ivideo->vbflags & TV_YPBPR750P)  cr38 |= 0x20;
3581                    else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3582                    cr31 &= ~0x01;
3583                    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3584                 }
3585#endif
3586              } else if((ivideo->vbflags & TV_HIVISION) &&
3587                                (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3588                 if(ivideo->chip >= SIS_661) {
3589                    cr38 |= 0x04;
3590                    cr35 |= 0x60;
3591                 } else {
3592                    cr30 |= 0x80;
3593                 }
3594                 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3595                 cr31 |= 0x01;
3596                 cr35 |= 0x01;
3597                 ivideo->currentvbflags |= TV_HIVISION;
3598              } else if(ivideo->vbflags & TV_SCART) {
3599                 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3600                 cr31 |= 0x01;
3601                 cr35 |= 0x01;
3602                 ivideo->currentvbflags |= TV_SCART;
3603              } else {
3604                 if(ivideo->vbflags & TV_SVIDEO) {
3605                    cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3606                    ivideo->currentvbflags |= TV_SVIDEO;
3607                 }
3608                 if(ivideo->vbflags & TV_AVIDEO) {
3609                    cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3610                    ivideo->currentvbflags |= TV_AVIDEO;
3611                 }
3612              }
3613              cr31 |= SIS_DRIVER_MODE;
3614
3615              if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3616                 if(ivideo->vbflags & TV_PAL) {
3617                    cr31 |= 0x01; cr35 |= 0x01;
3618                    ivideo->currentvbflags |= TV_PAL;
3619                    if(ivideo->vbflags & TV_PALM) {
3620                       cr38 |= 0x40; cr35 |= 0x04;
3621                       ivideo->currentvbflags |= TV_PALM;
3622                    } else if(ivideo->vbflags & TV_PALN) {
3623                       cr38 |= 0x80; cr35 |= 0x08;
3624                       ivideo->currentvbflags |= TV_PALN;
3625                    }
3626                 } else {
3627                    cr31 &= ~0x01; cr35 &= ~0x01;
3628                    ivideo->currentvbflags |= TV_NTSC;
3629                    if(ivideo->vbflags & TV_NTSCJ) {
3630                       cr38 |= 0x40; cr35 |= 0x02;
3631                       ivideo->currentvbflags |= TV_NTSCJ;
3632                    }
3633                 }
3634              }
3635              break;
3636
3637           case CRT2_LCD:
3638              cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3639              cr31 |= SIS_DRIVER_MODE;
3640              SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3641              SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3642              ivideo->curFSTN = ivideo->sisfb_fstn;
3643              ivideo->curDSTN = ivideo->sisfb_dstn;
3644              break;
3645
3646           case CRT2_VGA:
3647              cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3648              cr31 |= SIS_DRIVER_MODE;
3649              if(ivideo->sisfb_nocrt2rate) {
3650                 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3651              } else {
3652                 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3653              }
3654              break;
3655
3656           default:     /* disable CRT2 */
3657              cr30 = 0x00;
3658              cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3659        }
3660
3661        SiS_SetReg(SISCR, 0x30, cr30);
3662        SiS_SetReg(SISCR, 0x33, cr33);
3663
3664        if(ivideo->chip >= SIS_661) {
3665#ifdef CONFIG_FB_SIS_315
3666           cr31 &= ~0x01;                          /* Clear PAL flag (now in CR35) */
3667           SiS_SetRegANDOR(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3668           cr38 &= 0x07;                           /* Use only LCDA and HiVision/YPbPr bits */
3669           SiS_SetRegANDOR(SISCR, 0x38, 0xf8, cr38);
3670#endif
3671        } else if(ivideo->chip != SIS_300) {
3672           SiS_SetReg(SISCR, tvregnum, cr38);
3673        }
3674        SiS_SetReg(SISCR, 0x31, cr31);
3675
3676        ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3677
3678        sisfb_check_engine_and_sync(ivideo);
3679}
3680
3681/* Fix SR11 for 661 and later */
3682#ifdef CONFIG_FB_SIS_315
3683static void
3684sisfb_fixup_SR11(struct sis_video_info *ivideo)
3685{
3686        u8  tmpreg;
3687
3688        if(ivideo->chip >= SIS_661) {
3689                tmpreg = SiS_GetReg(SISSR, 0x11);
3690                if(tmpreg & 0x20) {
3691                        tmpreg = SiS_GetReg(SISSR, 0x3e);
3692                        tmpreg = (tmpreg + 1) & 0xff;
3693                        SiS_SetReg(SISSR, 0x3e, tmpreg);
3694                        tmpreg = SiS_GetReg(SISSR, 0x11);
3695                }
3696                if(tmpreg & 0xf0) {
3697                        SiS_SetRegAND(SISSR, 0x11, 0x0f);
3698                }
3699        }
3700}
3701#endif
3702
3703static void
3704sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3705{
3706        if(val > 32) val = 32;
3707        if(val < -32) val = -32;
3708        ivideo->tvxpos = val;
3709
3710        if(ivideo->sisfblocked) return;
3711        if(!ivideo->modechanged) return;
3712
3713        if(ivideo->currentvbflags & CRT2_TV) {
3714
3715                if(ivideo->vbflags2 & VB2_CHRONTEL) {
3716
3717                        int x = ivideo->tvx;
3718
3719                        switch(ivideo->chronteltype) {
3720                        case 1:
3721                                x += val;
3722                                if(x < 0) x = 0;
3723                                SiS_SetReg(SISSR, 0x05, 0x86);
3724                                SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3725                                SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3726                                break;
3727                        case 2:
3728                                /* Not supported by hardware */
3729                                break;
3730                        }
3731
3732                } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3733
3734                        u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3735                        unsigned short temp;
3736
3737                        p2_1f = ivideo->p2_1f;
3738                        p2_20 = ivideo->p2_20;
3739                        p2_2b = ivideo->p2_2b;
3740                        p2_42 = ivideo->p2_42;
3741                        p2_43 = ivideo->p2_43;
3742
3743                        temp = p2_1f | ((p2_20 & 0xf0) << 4);
3744                        temp += (val * 2);
3745                        p2_1f = temp & 0xff;
3746                        p2_20 = (temp & 0xf00) >> 4;
3747                        p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3748                        temp = p2_43 | ((p2_42 & 0xf0) << 4);
3749                        temp += (val * 2);
3750                        p2_43 = temp & 0xff;
3751                        p2_42 = (temp & 0xf00) >> 4;
3752                        SiS_SetReg(SISPART2, 0x1f, p2_1f);
3753                        SiS_SetRegANDOR(SISPART2, 0x20, 0x0F, p2_20);
3754                        SiS_SetRegANDOR(SISPART2, 0x2b, 0xF0, p2_2b);
3755                        SiS_SetRegANDOR(SISPART2, 0x42, 0x0F, p2_42);
3756                        SiS_SetReg(SISPART2, 0x43, p2_43);
3757                }
3758        }
3759}
3760
3761static void
3762sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3763{
3764        if(val > 32) val = 32;
3765        if(val < -32) val = -32;
3766        ivideo->tvypos = val;
3767
3768        if(ivideo->sisfblocked) return;
3769        if(!ivideo->modechanged) return;
3770
3771        if(ivideo->currentvbflags & CRT2_TV) {
3772
3773                if(ivideo->vbflags2 & VB2_CHRONTEL) {
3774
3775                        int y = ivideo->tvy;
3776
3777                        switch(ivideo->chronteltype) {
3778                        case 1:
3779                                y -= val;
3780                                if(y < 0) y = 0;
3781                                SiS_SetReg(SISSR, 0x05, 0x86);
3782                                SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3783                                SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3784                                break;
3785                        case 2:
3786                                /* Not supported by hardware */
3787                                break;
3788                        }
3789
3790                } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3791
3792                        char p2_01, p2_02;
3793                        val /= 2;
3794                        p2_01 = ivideo->p2_01;
3795                        p2_02 = ivideo->p2_02;
3796
3797                        p2_01 += val;
3798                        p2_02 += val;
3799                        if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3800                                while((p2_01 <= 0) || (p2_02 <= 0)) {
3801                                        p2_01 += 2;
3802                                        p2_02 += 2;
3803                                }
3804                        }
3805                        SiS_SetReg(SISPART2, 0x01, p2_01);
3806                        SiS_SetReg(SISPART2, 0x02, p2_02);
3807                }
3808        }
3809}
3810
3811static void
3812sisfb_post_setmode(struct sis_video_info *ivideo)
3813{
3814        bool crt1isoff = false;
3815        bool doit = true;
3816#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3817        u8 reg;
3818#endif
3819#ifdef CONFIG_FB_SIS_315
3820        u8 reg1;
3821#endif
3822
3823        SiS_SetReg(SISSR, 0x05, 0x86);
3824
3825#ifdef CONFIG_FB_SIS_315
3826        sisfb_fixup_SR11(ivideo);
3827#endif
3828
3829        /* Now we actually HAVE changed the display mode */
3830        ivideo->modechanged = 1;
3831
3832        /* We can't switch off CRT1 if bridge is in slave mode */
3833        if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3834                if(sisfb_bridgeisslave(ivideo)) doit = false;
3835        } else
3836                ivideo->sisfb_crt1off = 0;
3837
3838#ifdef CONFIG_FB_SIS_300
3839        if(ivideo->sisvga_engine == SIS_300_VGA) {
3840                if((ivideo->sisfb_crt1off) && (doit)) {
3841                        crt1isoff = true;
3842                        reg = 0x00;
3843                } else {
3844                        crt1isoff = false;
3845                        reg = 0x80;
3846                }
3847                SiS_SetRegANDOR(SISCR, 0x17, 0x7f, reg);
3848        }
3849#endif
3850#ifdef CONFIG_FB_SIS_315
3851        if(ivideo->sisvga_engine == SIS_315_VGA) {
3852                if((ivideo->sisfb_crt1off) && (doit)) {
3853                        crt1isoff = true;
3854                        reg  = 0x40;
3855                        reg1 = 0xc0;
3856                } else {
3857                        crt1isoff = false;
3858                        reg  = 0x00;
3859                        reg1 = 0x00;
3860                }
3861                SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3862                SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, reg1);
3863        }
3864#endif
3865
3866        if(crt1isoff) {
3867                ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3868                ivideo->currentvbflags |= VB_SINGLE_MODE;
3869        } else {
3870                ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3871                if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3872                        ivideo->currentvbflags |= VB_MIRROR_MODE;
3873                } else {
3874                        ivideo->currentvbflags |= VB_SINGLE_MODE;
3875                }
3876        }
3877
3878        SiS_SetRegAND(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3879
3880        if(ivideo->currentvbflags & CRT2_TV) {
3881                if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3882                        ivideo->p2_1f = SiS_GetReg(SISPART2, 0x1f);
3883                        ivideo->p2_20 = SiS_GetReg(SISPART2, 0x20);
3884                        ivideo->p2_2b = SiS_GetReg(SISPART2, 0x2b);
3885                        ivideo->p2_42 = SiS_GetReg(SISPART2, 0x42);
3886                        ivideo->p2_43 = SiS_GetReg(SISPART2, 0x43);
3887                        ivideo->p2_01 = SiS_GetReg(SISPART2, 0x01);
3888                        ivideo->p2_02 = SiS_GetReg(SISPART2, 0x02);
3889                } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3890                        if(ivideo->chronteltype == 1) {
3891                                ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3892                                ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3893                                ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3894                                ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3895                        }
3896                }
3897        }
3898
3899        if(ivideo->tvxpos) {
3900                sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3901        }
3902        if(ivideo->tvypos) {
3903                sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3904        }
3905
3906        /* Eventually sync engines */
3907        sisfb_check_engine_and_sync(ivideo);
3908
3909        /* (Re-)Initialize chip engines */
3910        if(ivideo->accel) {
3911                sisfb_engine_init(ivideo);
3912        } else {
3913                ivideo->engineok = 0;
3914        }
3915}
3916
3917static int
3918sisfb_reset_mode(struct sis_video_info *ivideo)
3919{
3920        if(sisfb_set_mode(ivideo, 0))
3921                return 1;
3922
3923        sisfb_set_pitch(ivideo);
3924        sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3925        sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3926
3927        return 0;
3928}
3929
3930static void
3931sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3932{
3933        int mycrt1off;
3934
3935        switch(sisfb_command->sisfb_cmd) {
3936        case SISFB_CMD_GETVBFLAGS:
3937                if(!ivideo->modechanged) {
3938                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3939                } else {
3940                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3941                        sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3942                        sisfb_command->sisfb_result[2] = ivideo->vbflags2;
3943                }
3944                break;
3945        case SISFB_CMD_SWITCHCRT1:
3946                /* arg[0]: 0 = off, 1 = on, 99 = query */
3947                if(!ivideo->modechanged) {
3948                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3949                } else if(sisfb_command->sisfb_arg[0] == 99) {
3950                        /* Query */
3951                        sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3952                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3953                } else if(ivideo->sisfblocked) {
3954                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3955                } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3956                                        (sisfb_command->sisfb_arg[0] == 0)) {
3957                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3958                } else {
3959                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3960                        mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3961                        if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3962                            ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3963                                ivideo->sisfb_crt1off = mycrt1off;
3964                                if(sisfb_reset_mode(ivideo)) {
3965                                        sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
3966                                }
3967                        }
3968                        sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3969                }
3970                break;
3971        /* more to come */
3972        default:
3973                sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3974                printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3975                        sisfb_command->sisfb_cmd);
3976        }
3977}
3978
3979#ifndef MODULE
3980static int __init sisfb_setup(char *options)
3981{
3982        char *this_opt;
3983
3984        sisfb_setdefaultparms();
3985
3986        if(!options || !(*options))
3987                return 0;
3988
3989        while((this_opt = strsep(&options, ",")) != NULL) {
3990
3991                if(!(*this_opt)) continue;
3992
3993                if(!strncasecmp(this_opt, "off", 3)) {
3994                        sisfb_off = 1;
3995                } else if(!strncasecmp(this_opt, "forcecrt2type:", 14)) {
3996                        /* Need to check crt2 type first for fstn/dstn */
3997                        sisfb_search_crt2type(this_opt + 14);
3998                } else if(!strncasecmp(this_opt, "tvmode:",7)) {
3999                        sisfb_search_tvstd(this_opt + 7);
4000                } else if(!strncasecmp(this_opt, "tvstandard:",11)) {
4001                        sisfb_search_tvstd(this_opt + 11);
4002                } else if(!strncasecmp(this_opt, "mode:", 5)) {
4003                        sisfb_search_mode(this_opt + 5, false);
4004                } else if(!strncasecmp(this_opt, "vesa:", 5)) {
4005                        sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
4006                } else if(!strncasecmp(this_opt, "rate:", 5)) {
4007                        sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
4008                } else if(!strncasecmp(this_opt, "forcecrt1:", 10)) {
4009                        sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4010                } else if(!strncasecmp(this_opt, "mem:",4)) {
4011                        sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4012                } else if(!strncasecmp(this_opt, "pdc:", 4)) {
4013                        sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4014                } else if(!strncasecmp(this_opt, "pdc1:", 5)) {
4015                        sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4016                } else if(!strncasecmp(this_opt, "noaccel", 7)) {
4017                        sisfb_accel = 0;
4018                } else if(!strncasecmp(this_opt, "accel", 5)) {
4019                        sisfb_accel = -1;
4020                } else if(!strncasecmp(this_opt, "noypan", 6)) {
4021                        sisfb_ypan = 0;
4022                } else if(!strncasecmp(this_opt, "ypan", 4)) {
4023                        sisfb_ypan = -1;
4024                } else if(!strncasecmp(this_opt, "nomax", 5)) {
4025                        sisfb_max = 0;
4026                } else if(!strncasecmp(this_opt, "max", 3)) {
4027                        sisfb_max = -1;
4028                } else if(!strncasecmp(this_opt, "userom:", 7)) {
4029                        sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4030                } else if(!strncasecmp(this_opt, "useoem:", 7)) {
4031                        sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4032                } else if(!strncasecmp(this_opt, "nocrt2rate", 10)) {
4033                        sisfb_nocrt2rate = 1;
4034                } else if(!strncasecmp(this_opt, "scalelcd:", 9)) {
4035                        unsigned long temp = 2;
4036                        temp = simple_strtoul(this_opt + 9, NULL, 0);
4037                        if((temp == 0) || (temp == 1)) {
4038                           sisfb_scalelcd = temp ^ 1;
4039                        }
4040                } else if(!strncasecmp(this_opt, "tvxposoffset:", 13)) {
4041                        int temp = 0;
4042                        temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4043                        if((temp >= -32) && (temp <= 32)) {
4044                           sisfb_tvxposoffset = temp;
4045                        }
4046                } else if(!strncasecmp(this_opt, "tvyposoffset:", 13)) {
4047                        int temp = 0;
4048                        temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4049                        if((temp >= -32) && (temp <= 32)) {
4050                           sisfb_tvyposoffset = temp;
4051                        }
4052                } else if(!strncasecmp(this_opt, "specialtiming:", 14)) {
4053                        sisfb_search_specialtiming(this_opt + 14);
4054                } else if(!strncasecmp(this_opt, "lvdshl:", 7)) {
4055                        int temp = 4;
4056                        temp = simple_strtoul(this_opt + 7, NULL, 0);
4057                        if((temp >= 0) && (temp <= 3)) {
4058                           sisfb_lvdshl = temp;
4059                        }
4060                } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4061                        sisfb_search_mode(this_opt, true);
4062#if !defined(__i386__) && !defined(__x86_64__)
4063                } else if(!strncasecmp(this_opt, "resetcard", 9)) {
4064                        sisfb_resetcard = 1;
4065                } else if(!strncasecmp(this_opt, "videoram:", 9)) {
4066                        sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4067#endif
4068                } else {
4069                        printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4070                }
4071
4072        }
4073
4074        return 0;
4075}
4076#endif
4077
4078static int sisfb_check_rom(void __iomem *rom_base,
4079                           struct sis_video_info *ivideo)
4080{
4081        void __iomem *rom;
4082        int romptr;
4083
4084        if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4085                return 0;
4086
4087        romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4088        if(romptr > (0x10000 - 8))
4089                return 0;
4090
4091        rom = rom_base + romptr;
4092
4093        if((readb(rom)     != 'P') || (readb(rom + 1) != 'C') ||
4094           (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4095                return 0;
4096
4097        if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4098                return 0;
4099
4100        if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4101                return 0;
4102
4103        return 1;
4104}
4105
4106static unsigned char *sisfb_find_rom(struct pci_dev *pdev)
4107{
4108        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4109        void __iomem *rom_base;
4110        unsigned char *myrombase = NULL;
4111        size_t romsize;
4112
4113        /* First, try the official pci ROM functions (except
4114         * on integrated chipsets which have no ROM).
4115         */
4116
4117        if(!ivideo->nbridge) {
4118
4119                if((rom_base = pci_map_rom(pdev, &romsize))) {
4120
4121                        if(sisfb_check_rom(rom_base, ivideo)) {
4122
4123                                if((myrombase = vmalloc(65536))) {
4124                                        memcpy_fromio(myrombase, rom_base,
4125                                                        (romsize > 65536) ? 65536 : romsize);
4126                                }
4127                        }
4128                        pci_unmap_rom(pdev, rom_base);
4129                }
4130        }
4131
4132        if(myrombase) return myrombase;
4133
4134        /* Otherwise do it the conventional way. */
4135
4136#if defined(__i386__) || defined(__x86_64__)
4137        {
4138                u32 temp;
4139
4140                for (temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4141
4142                        rom_base = ioremap(temp, 65536);
4143                        if (!rom_base)
4144                                continue;
4145
4146                        if (!sisfb_check_rom(rom_base, ivideo)) {
4147                                iounmap(rom_base);
4148                                continue;
4149                        }
4150
4151                        if ((myrombase = vmalloc(65536)))
4152                                memcpy_fromio(myrombase, rom_base, 65536);
4153
4154                        iounmap(rom_base);
4155                        break;
4156
4157                }
4158
4159        }
4160#endif
4161
4162        return myrombase;
4163}
4164
4165static void sisfb_post_map_vram(struct sis_video_info *ivideo,
4166                                unsigned int *mapsize, unsigned int min)
4167{
4168        if (*mapsize < (min << 20))
4169                return;
4170
4171        ivideo->video_vbase = ioremap_wc(ivideo->video_base, (*mapsize));
4172
4173        if(!ivideo->video_vbase) {
4174                printk(KERN_ERR
4175                        "sisfb: Unable to map maximum video RAM for size detection\n");
4176                (*mapsize) >>= 1;
4177                while((!(ivideo->video_vbase = ioremap_wc(ivideo->video_base, (*mapsize))))) {
4178                        (*mapsize) >>= 1;
4179                        if((*mapsize) < (min << 20))
4180                                break;
4181                }
4182                if(ivideo->video_vbase) {
4183                        printk(KERN_ERR
4184                                "sisfb: Video RAM size detection limited to %dMB\n",
4185                                (int)((*mapsize) >> 20));
4186                }
4187        }
4188}
4189
4190#ifdef CONFIG_FB_SIS_300
4191static int sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4192{
4193        void __iomem *FBAddress = ivideo->video_vbase;
4194        unsigned short temp;
4195        unsigned char reg;
4196        int i, j;
4197
4198        SiS_SetRegAND(SISSR, 0x15, 0xFB);
4199        SiS_SetRegOR(SISSR, 0x15, 0x04);
4200        SiS_SetReg(SISSR, 0x13, 0x00);
4201        SiS_SetReg(SISSR, 0x14, 0xBF);
4202
4203        for(i = 0; i < 2; i++) {
4204                temp = 0x1234;
4205                for(j = 0; j < 4; j++) {
4206                        writew(temp, FBAddress);
4207                        if(readw(FBAddress) == temp)
4208                                break;
4209                        SiS_SetRegOR(SISSR, 0x3c, 0x01);
4210                        reg = SiS_GetReg(SISSR, 0x05);
4211                        reg = SiS_GetReg(SISSR, 0x05);
4212                        SiS_SetRegAND(SISSR, 0x3c, 0xfe);
4213                        reg = SiS_GetReg(SISSR, 0x05);
4214                        reg = SiS_GetReg(SISSR, 0x05);
4215                        temp++;
4216                }
4217        }
4218
4219        writel(0x01234567L, FBAddress);
4220        writel(0x456789ABL, (FBAddress + 4));
4221        writel(0x89ABCDEFL, (FBAddress + 8));
4222        writel(0xCDEF0123L, (FBAddress + 12));
4223
4224        reg = SiS_GetReg(SISSR, 0x3b);
4225        if(reg & 0x01) {
4226                if(readl((FBAddress + 12)) == 0xCDEF0123L)
4227                        return 4;       /* Channel A 128bit */
4228        }
4229
4230        if(readl((FBAddress + 4)) == 0x456789ABL)
4231                return 2;               /* Channel B 64bit */
4232
4233        return 1;                       /* 32bit */
4234}
4235
4236static const unsigned short SiS_DRAMType[17][5] = {
4237        {0x0C,0x0A,0x02,0x40,0x39},
4238        {0x0D,0x0A,0x01,0x40,0x48},
4239        {0x0C,0x09,0x02,0x20,0x35},
4240        {0x0D,0x09,0x01,0x20,0x44},
4241        {0x0C,0x08,0x02,0x10,0x31},
4242        {0x0D,0x08,0x01,0x10,0x40},
4243        {0x0C,0x0A,0x01,0x20,0x34},
4244        {0x0C,0x09,0x01,0x08,0x32},
4245        {0x0B,0x08,0x02,0x08,0x21},
4246        {0x0C,0x08,0x01,0x08,0x30},
4247        {0x0A,0x08,0x02,0x04,0x11},
4248        {0x0B,0x0A,0x01,0x10,0x28},
4249        {0x09,0x08,0x02,0x02,0x01},
4250        {0x0B,0x09,0x01,0x08,0x24},
4251        {0x0B,0x08,0x01,0x04,0x20},
4252        {0x0A,0x08,0x01,0x02,0x10},
4253        {0x09,0x08,0x01,0x01,0x00}
4254};
4255
4256static int sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration,
4257                                 int buswidth, int PseudoRankCapacity,
4258                                 int PseudoAdrPinCount, unsigned int mapsize)
4259{
4260        void __iomem *FBAddr = ivideo->video_vbase;
4261        unsigned short sr14;
4262        unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4263        unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4264
4265         for(k = 0; k < ARRAY_SIZE(SiS_DRAMType); k++) {
4266
4267                RankCapacity = buswidth * SiS_DRAMType[k][3];
4268
4269                if(RankCapacity != PseudoRankCapacity)
4270                        continue;
4271
4272                if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4273                        continue;
4274
4275                BankNumHigh = RankCapacity * 16 * iteration - 1;
4276                if(iteration == 3) {             /* Rank No */
4277                        BankNumMid  = RankCapacity * 16 - 1;
4278                } else {
4279                        BankNumMid  = RankCapacity * 16 * iteration / 2 - 1;
4280                }
4281
4282                PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4283                PhysicalAdrHigh = BankNumHigh;
4284                PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4285                PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4286
4287                SiS_SetRegAND(SISSR, 0x15, 0xFB); /* Test */
4288                SiS_SetRegOR(SISSR, 0x15, 0x04);  /* Test */
4289                sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4290                if(buswidth == 4)      sr14 |= 0x80;
4291                else if(buswidth == 2) sr14 |= 0x40;
4292                SiS_SetReg(SISSR, 0x13, SiS_DRAMType[k][4]);
4293                SiS_SetReg(SISSR, 0x14, sr14);
4294
4295                BankNumHigh <<= 16;
4296                BankNumMid <<= 16;
4297
4298                if((BankNumHigh + PhysicalAdrHigh      >= mapsize) ||
4299                   (BankNumMid  + PhysicalAdrHigh      >= mapsize) ||
4300                   (BankNumHigh + PhysicalAdrHalfPage  >= mapsize) ||
4301                   (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4302                        continue;
4303
4304                /* Write data */
4305                writew(((unsigned short)PhysicalAdrHigh),
4306                                (FBAddr + BankNumHigh + PhysicalAdrHigh));
4307                writew(((unsigned short)BankNumMid),
4308                                (FBAddr + BankNumMid  + PhysicalAdrHigh));
4309                writew(((unsigned short)PhysicalAdrHalfPage),
4310                                (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4311                writew(((unsigned short)PhysicalAdrOtherPage),
4312                                (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4313
4314                /* Read data */
4315                if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4316                        return 1;
4317        }
4318
4319        return 0;
4320}
4321
4322static void sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4323{
4324        struct  sis_video_info *ivideo = pci_get_drvdata(pdev);
4325        int     i, j, buswidth;
4326        int     PseudoRankCapacity, PseudoAdrPinCount;
4327
4328        buswidth = sisfb_post_300_buswidth(ivideo);
4329
4330        for(i = 6; i >= 0; i--) {
4331                PseudoRankCapacity = 1 << i;
4332                for(j = 4; j >= 1; j--) {
4333                        PseudoAdrPinCount = 15 - j;
4334                        if((PseudoRankCapacity * j) <= 64) {
4335                                if(sisfb_post_300_rwtest(ivideo,
4336                                                j,
4337                                                buswidth,
4338                                                PseudoRankCapacity,
4339                                                PseudoAdrPinCount,
4340                                                mapsize))
4341                                        return;
4342                        }
4343                }
4344        }
4345}
4346
4347static void sisfb_post_sis300(struct pci_dev *pdev)
4348{
4349        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4350        unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4351        u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
4352        u16 index, rindex, memtype = 0;
4353        unsigned int mapsize;
4354
4355        if(!ivideo->SiS_Pr.UseROM)
4356                bios = NULL;
4357
4358        SiS_SetReg(SISSR, 0x05, 0x86);
4359
4360        if(bios) {
4361                if(bios[0x52] & 0x80) {
4362                        memtype = bios[0x52];
4363                } else {
4364                        memtype = SiS_GetReg(SISSR, 0x3a);
4365                }
4366                memtype &= 0x07;
4367        }
4368
4369        v3 = 0x80; v6 = 0x80;
4370        if(ivideo->revision_id <= 0x13) {
4371                v1 = 0x44; v2 = 0x42;
4372                v4 = 0x44; v5 = 0x42;
4373        } else {
4374                v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4375                v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4376                if(bios) {
4377                        index = memtype * 5;
4378                        rindex = index + 0x54;
4379                        v1 = bios[rindex++];
4380                        v2 = bios[rindex++];
4381                        v3 = bios[rindex++];
4382                        rindex = index + 0x7c;
4383                        v4 = bios[rindex++];
4384                        v5 = bios[rindex++];
4385                        v6 = bios[rindex++];
4386                }
4387        }
4388        SiS_SetReg(SISSR, 0x28, v1);
4389        SiS_SetReg(SISSR, 0x29, v2);
4390        SiS_SetReg(SISSR, 0x2a, v3);
4391        SiS_SetReg(SISSR, 0x2e, v4);
4392        SiS_SetReg(SISSR, 0x2f, v5);
4393        SiS_SetReg(SISSR, 0x30, v6);
4394
4395        v1 = 0x10;
4396        if(bios)
4397                v1 = bios[0xa4];
4398        SiS_SetReg(SISSR, 0x07, v1);       /* DAC speed */
4399
4400        SiS_SetReg(SISSR, 0x11, 0x0f);     /* DDC, power save */
4401
4402        v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4403        v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4404        if(bios) {
4405                memtype += 0xa5;
4406                v1 = bios[memtype];
4407                v2 = bios[memtype + 8];
4408                v3 = bios[memtype + 16];
4409                v4 = bios[memtype + 24];
4410                v5 = bios[memtype + 32];
4411                v6 = bios[memtype + 40];
4412                v7 = bios[memtype + 48];
4413                v8 = bios[memtype + 56];
4414        }
4415        if(ivideo->revision_id >= 0x80)
4416                v3 &= 0xfd;
4417        SiS_SetReg(SISSR, 0x15, v1);       /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4418        SiS_SetReg(SISSR, 0x16, v2);
4419        SiS_SetReg(SISSR, 0x17, v3);
4420        SiS_SetReg(SISSR, 0x18, v4);
4421        SiS_SetReg(SISSR, 0x19, v5);
4422        SiS_SetReg(SISSR, 0x1a, v6);
4423        SiS_SetReg(SISSR, 0x1b, v7);
4424        SiS_SetReg(SISSR, 0x1c, v8);       /* ---- */
4425        SiS_SetRegAND(SISSR, 0x15, 0xfb);
4426        SiS_SetRegOR(SISSR, 0x15, 0x04);
4427        if(bios) {
4428                if(bios[0x53] & 0x02) {
4429                        SiS_SetRegOR(SISSR, 0x19, 0x20);
4430                }
4431        }
4432        v1 = 0x04;                         /* DAC pedestal (BIOS 0xe5) */
4433        if(ivideo->revision_id >= 0x80)
4434                v1 |= 0x01;
4435        SiS_SetReg(SISSR, 0x1f, v1);
4436        SiS_SetReg(SISSR, 0x20, 0xa4);     /* linear & relocated io & disable a0000 */
4437        v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4438        if(bios) {
4439                v1 = bios[0xe8];
4440                v2 = bios[0xe9];
4441                v3 = bios[0xea];
4442        }
4443        SiS_SetReg(SISSR, 0x23, v1);
4444        SiS_SetReg(SISSR, 0x24, v2);
4445        SiS_SetReg(SISSR, 0x25, v3);
4446        SiS_SetReg(SISSR, 0x21, 0x84);
4447        SiS_SetReg(SISSR, 0x22, 0x00);
4448        SiS_SetReg(SISCR, 0x37, 0x00);
4449        SiS_SetRegOR(SISPART1, 0x24, 0x01);   /* unlock crt2 */
4450        SiS_SetReg(SISPART1, 0x00, 0x00);
4451        v1 = 0x40; v2 = 0x11;
4452        if(bios) {
4453                v1 = bios[0xec];
4454                v2 = bios[0xeb];
4455        }
4456        SiS_SetReg(SISPART1, 0x02, v1);
4457
4458        if(ivideo->revision_id >= 0x80)
4459                v2 &= ~0x01;
4460
4461        reg = SiS_GetReg(SISPART4, 0x00);
4462        if((reg == 1) || (reg == 2)) {
4463                SiS_SetReg(SISCR, 0x37, 0x02);
4464                SiS_SetReg(SISPART2, 0x00, 0x1c);
4465                v4 = 0x00; v5 = 0x00; v6 = 0x10;
4466                if(ivideo->SiS_Pr.UseROM) {
4467                        v4 = bios[0xf5];
4468                        v5 = bios[0xf6];
4469                        v6 = bios[0xf7];
4470                }
4471                SiS_SetReg(SISPART4, 0x0d, v4);
4472                SiS_SetReg(SISPART4, 0x0e, v5);
4473                SiS_SetReg(SISPART4, 0x10, v6);
4474                SiS_SetReg(SISPART4, 0x0f, 0x3f);
4475                reg = SiS_GetReg(SISPART4, 0x01);
4476                if(reg >= 0xb0) {
4477                        reg = SiS_GetReg(SISPART4, 0x23);
4478                        reg &= 0x20;
4479                        reg <<= 1;
4480                        SiS_SetReg(SISPART4, 0x23, reg);
4481                }
4482        } else {
4483                v2 &= ~0x10;
4484        }
4485        SiS_SetReg(SISSR, 0x32, v2);
4486
4487        SiS_SetRegAND(SISPART1, 0x24, 0xfe);  /* Lock CRT2 */
4488
4489        reg = SiS_GetReg(SISSR, 0x16);
4490        reg &= 0xc3;
4491        SiS_SetReg(SISCR, 0x35, reg);
4492        SiS_SetReg(SISCR, 0x83, 0x00);
4493#if !defined(__i386__) && !defined(__x86_64__)
4494        if(sisfb_videoram) {
4495                SiS_SetReg(SISSR, 0x13, 0x28);  /* ? */
4496                reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4497                SiS_SetReg(SISSR, 0x14, reg);
4498        } else {
4499#endif
4500                /* Need to map max FB size for finding out about RAM size */
4501                mapsize = ivideo->video_size;
4502                sisfb_post_map_vram(ivideo, &mapsize, 4);
4503
4504                if(ivideo->video_vbase) {
4505                        sisfb_post_300_ramsize(pdev, mapsize);
4506                        iounmap(ivideo->video_vbase);
4507                } else {
4508                        printk(KERN_DEBUG
4509                                "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4510                        SiS_SetReg(SISSR, 0x13, 0x28);  /* ? */
4511                        SiS_SetReg(SISSR, 0x14, 0x47);  /* 8MB, 64bit default */
4512                }
4513#if !defined(__i386__) && !defined(__x86_64__)
4514        }
4515#endif
4516        if(bios) {
4517                v1 = bios[0xe6];
4518                v2 = bios[0xe7];
4519        } else {
4520                reg = SiS_GetReg(SISSR, 0x3a);
4521                if((reg & 0x30) == 0x30) {
4522                        v1 = 0x04; /* PCI */
4523                        v2 = 0x92;
4524                } else {
4525                        v1 = 0x14; /* AGP */
4526                        v2 = 0xb2;
4527                }
4528        }
4529        SiS_SetReg(SISSR, 0x21, v1);
4530        SiS_SetReg(SISSR, 0x22, v2);
4531
4532        /* Sense CRT1 */
4533        sisfb_sense_crt1(ivideo);
4534
4535        /* Set default mode, don't clear screen */
4536        ivideo->SiS_Pr.SiS_UseOEM = false;
4537        SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4538        SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
4539        ivideo->curFSTN = ivideo->curDSTN = 0;
4540        ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4541        SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4542
4543        SiS_SetReg(SISSR, 0x05, 0x86);
4544
4545        /* Display off */
4546        SiS_SetRegOR(SISSR, 0x01, 0x20);
4547
4548        /* Save mode number in CR34 */
4549        SiS_SetReg(SISCR, 0x34, 0x2e);
4550
4551        /* Let everyone know what the current mode is */
4552        ivideo->modeprechange = 0x2e;
4553}
4554#endif
4555
4556#ifdef CONFIG_FB_SIS_315
4557#if 0
4558static void sisfb_post_sis315330(struct pci_dev *pdev)
4559{
4560        /* TODO */
4561}
4562#endif
4563
4564static inline int sisfb_xgi_is21(struct sis_video_info *ivideo)
4565{
4566        return ivideo->chip_real_id == XGI_21;
4567}
4568
4569static void sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4570{
4571        unsigned int i;
4572        u8 reg;
4573
4574        for(i = 0; i <= (delay * 10 * 36); i++) {
4575                reg = SiS_GetReg(SISSR, 0x05);
4576                reg++;
4577        }
4578}
4579
4580static int sisfb_find_host_bridge(struct sis_video_info *ivideo,
4581                                  struct pci_dev *mypdev,
4582                                  unsigned short pcivendor)
4583{
4584        struct pci_dev *pdev = NULL;
4585        unsigned short temp;
4586        int ret = 0;
4587
4588        while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
4589                temp = pdev->vendor;
4590                if(temp == pcivendor) {
4591                        ret = 1;
4592                        pci_dev_put(pdev);
4593                        break;
4594                }
4595        }
4596
4597        return ret;
4598}
4599
4600static int sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4601                                 unsigned int enda, unsigned int mapsize)
4602{
4603        unsigned int pos;
4604        int i;
4605
4606        writel(0, ivideo->video_vbase);
4607
4608        for(i = starta; i <= enda; i++) {
4609                pos = 1 << i;
4610                if(pos < mapsize)
4611                        writel(pos, ivideo->video_vbase + pos);
4612        }
4613
4614        sisfb_post_xgi_delay(ivideo, 150);
4615
4616        if(readl(ivideo->video_vbase) != 0)
4617                return 0;
4618
4619        for(i = starta; i <= enda; i++) {
4620                pos = 1 << i;
4621                if(pos < mapsize) {
4622                        if(readl(ivideo->video_vbase + pos) != pos)
4623                                return 0;
4624                } else
4625                        return 0;
4626        }
4627
4628        return 1;
4629}
4630
4631static int sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4632{
4633        unsigned int buswidth, ranksize, channelab, mapsize;
4634        int i, j, k, l, status;
4635        u8 reg, sr14;
4636        static const u8 dramsr13[12 * 5] = {
4637                0x02, 0x0e, 0x0b, 0x80, 0x5d,
4638                0x02, 0x0e, 0x0a, 0x40, 0x59,
4639                0x02, 0x0d, 0x0b, 0x40, 0x4d,
4640                0x02, 0x0e, 0x09, 0x20, 0x55,
4641                0x02, 0x0d, 0x0a, 0x20, 0x49,
4642                0x02, 0x0c, 0x0b, 0x20, 0x3d,
4643                0x02, 0x0e, 0x08, 0x10, 0x51,
4644                0x02, 0x0d, 0x09, 0x10, 0x45,
4645                0x02, 0x0c, 0x0a, 0x10, 0x39,
4646                0x02, 0x0d, 0x08, 0x08, 0x41,
4647                0x02, 0x0c, 0x09, 0x08, 0x35,
4648                0x02, 0x0c, 0x08, 0x04, 0x31
4649        };
4650        static const u8 dramsr13_4[4 * 5] = {
4651                0x02, 0x0d, 0x09, 0x40, 0x45,
4652                0x02, 0x0c, 0x09, 0x20, 0x35,
4653                0x02, 0x0c, 0x08, 0x10, 0x31,
4654                0x02, 0x0b, 0x08, 0x08, 0x21
4655        };
4656
4657        /* Enable linear mode, disable 0xa0000 address decoding */
4658        /* We disable a0000 address decoding, because
4659         * - if running on x86, if the card is disabled, it means
4660         *   that another card is in the system. We don't want
4661         *   to interphere with that primary card's textmode.
4662         * - if running on non-x86, there usually is no VGA window
4663         *   at a0000.
4664         */
4665        SiS_SetRegOR(SISSR, 0x20, (0x80 | 0x04));
4666
4667        /* Need to map max FB size for finding out about RAM size */
4668        mapsize = ivideo->video_size;
4669        sisfb_post_map_vram(ivideo, &mapsize, 32);
4670
4671        if(!ivideo->video_vbase) {
4672                printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4673                SiS_SetReg(SISSR, 0x13, 0x35);
4674                SiS_SetReg(SISSR, 0x14, 0x41);
4675                /* TODO */
4676                return -ENOMEM;
4677        }
4678
4679        /* Non-interleaving */
4680        SiS_SetReg(SISSR, 0x15, 0x00);
4681        /* No tiling */
4682        SiS_SetReg(SISSR, 0x1c, 0x00);
4683
4684        if(ivideo->chip == XGI_20) {
4685
4686                channelab = 1;
4687                reg = SiS_GetReg(SISCR, 0x97);
4688                if(!(reg & 0x01)) {     /* Single 32/16 */
4689                        buswidth = 32;
4690                        SiS_SetReg(SISSR, 0x13, 0xb1);
4691                        SiS_SetReg(SISSR, 0x14, 0x52);
4692                        sisfb_post_xgi_delay(ivideo, 1);
4693                        sr14 = 0x02;
4694                        if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4695                                goto bail_out;
4696
4697                        SiS_SetReg(SISSR, 0x13, 0x31);
4698                        SiS_SetReg(SISSR, 0x14, 0x42);
4699                        sisfb_post_xgi_delay(ivideo, 1);
4700                        if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4701                                goto bail_out;
4702
4703                        buswidth = 16;
4704                        SiS_SetReg(SISSR, 0x13, 0xb1);
4705                        SiS_SetReg(SISSR, 0x14, 0x41);
4706                        sisfb_post_xgi_delay(ivideo, 1);
4707                        sr14 = 0x01;
4708                        if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4709                                goto bail_out;
4710                        else
4711                                SiS_SetReg(SISSR, 0x13, 0x31);
4712                } else {                /* Dual 16/8 */
4713                        buswidth = 16;
4714                        SiS_SetReg(SISSR, 0x13, 0xb1);
4715                        SiS_SetReg(SISSR, 0x14, 0x41);
4716                        sisfb_post_xgi_delay(ivideo, 1);
4717                        sr14 = 0x01;
4718                        if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4719                                goto bail_out;
4720
4721                        SiS_SetReg(SISSR, 0x13, 0x31);
4722                        SiS_SetReg(SISSR, 0x14, 0x31);
4723                        sisfb_post_xgi_delay(ivideo, 1);
4724                        if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4725                                goto bail_out;
4726
4727                        buswidth = 8;
4728                        SiS_SetReg(SISSR, 0x13, 0xb1);
4729                        SiS_SetReg(SISSR, 0x14, 0x30);
4730                        sisfb_post_xgi_delay(ivideo, 1);
4731                        sr14 = 0x00;
4732                        if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4733                                goto bail_out;
4734                        else
4735                                SiS_SetReg(SISSR, 0x13, 0x31);
4736                }
4737
4738        } else {        /* XGI_40 */
4739
4740                reg = SiS_GetReg(SISCR, 0x97);
4741                if(!(reg & 0x10)) {
4742                        reg = SiS_GetReg(SISSR, 0x39);
4743                        reg >>= 1;
4744                }
4745
4746                if(reg & 0x01) {        /* DDRII */
4747                        buswidth = 32;
4748                        if(ivideo->revision_id == 2) {
4749                                channelab = 2;
4750                                SiS_SetReg(SISSR, 0x13, 0xa1);
4751                                SiS_SetReg(SISSR, 0x14, 0x44);
4752                                sr14 = 0x04;
4753                                sisfb_post_xgi_delay(ivideo, 1);
4754                                if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4755                                        goto bail_out;
4756
4757                                SiS_SetReg(SISSR, 0x13, 0x21);
4758                                SiS_SetReg(SISSR, 0x14, 0x34);
4759                                if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4760                                        goto bail_out;
4761
4762                                channelab = 1;
4763                                SiS_SetReg(SISSR, 0x13, 0xa1);
4764                                SiS_SetReg(SISSR, 0x14, 0x40);
4765                                sr14 = 0x00;
4766                                if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4767                                        goto bail_out;
4768
4769                                SiS_SetReg(SISSR, 0x13, 0x21);
4770                                SiS_SetReg(SISSR, 0x14, 0x30);
4771                        } else {
4772                                channelab = 3;
4773                                SiS_SetReg(SISSR, 0x13, 0xa1);
4774                                SiS_SetReg(SISSR, 0x14, 0x4c);
4775                                sr14 = 0x0c;
4776                                sisfb_post_xgi_delay(ivideo, 1);
4777                                if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4778                                        goto bail_out;
4779
4780                                channelab = 2;
4781                                SiS_SetReg(SISSR, 0x14, 0x48);
4782                                sisfb_post_xgi_delay(ivideo, 1);
4783                                sr14 = 0x08;
4784                                if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4785                                        goto bail_out;
4786
4787                                SiS_SetReg(SISSR, 0x13, 0x21);
4788                                SiS_SetReg(SISSR, 0x14, 0x3c);
4789                                sr14 = 0x0c;
4790
4791                                if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4792                                        channelab = 3;
4793                                } else {
4794                                        channelab = 2;
4795                                        SiS_SetReg(SISSR, 0x14, 0x38);
4796                                        sr14 = 0x08;
4797                                }
4798                        }
4799                        sisfb_post_xgi_delay(ivideo, 1);
4800
4801                } else {        /* DDR */
4802
4803                        buswidth = 64;
4804                        if(ivideo->revision_id == 2) {
4805                                channelab = 1;
4806                                SiS_SetReg(SISSR, 0x13, 0xa1);
4807                                SiS_SetReg(SISSR, 0x14, 0x52);
4808                                sisfb_post_xgi_delay(ivideo, 1);
4809                                sr14 = 0x02;
4810                                if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4811                                        goto bail_out;
4812
4813                                SiS_SetReg(SISSR, 0x13, 0x21);
4814                                SiS_SetReg(SISSR, 0x14, 0x42);
4815                        } else {
4816                                channelab = 2;
4817                                SiS_SetReg(SISSR, 0x13, 0xa1);
4818                                SiS_SetReg(SISSR, 0x14, 0x5a);
4819                                sisfb_post_xgi_delay(ivideo, 1);
4820                                sr14 = 0x0a;
4821                                if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4822                                        goto bail_out;
4823
4824                                SiS_SetReg(SISSR, 0x13, 0x21);
4825                                SiS_SetReg(SISSR, 0x14, 0x4a);
4826                        }
4827                        sisfb_post_xgi_delay(ivideo, 1);
4828
4829                }
4830        }
4831
4832bail_out:
4833        SiS_SetRegANDOR(SISSR, 0x14, 0xf0, sr14);
4834        sisfb_post_xgi_delay(ivideo, 1);
4835
4836        j = (ivideo->chip == XGI_20) ? 5 : 9;
4837        k = (ivideo->chip == XGI_20) ? 12 : 4;
4838        status = -EIO;
4839
4840        for(i = 0; i < k; i++) {
4841
4842                reg = (ivideo->chip == XGI_20) ?
4843                                dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4844                SiS_SetRegANDOR(SISSR, 0x13, 0x80, reg);
4845                sisfb_post_xgi_delay(ivideo, 50);
4846
4847                ranksize = (ivideo->chip == XGI_20) ?
4848                                dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4849
4850                reg = SiS_GetReg(SISSR, 0x13);
4851                if(reg & 0x80) ranksize <<= 1;
4852
4853                if(ivideo->chip == XGI_20) {
4854                        if(buswidth == 16)      ranksize <<= 1;
4855                        else if(buswidth == 32) ranksize <<= 2;
4856                } else {
4857                        if(buswidth == 64)      ranksize <<= 1;
4858                }
4859
4860                reg = 0;
4861                l = channelab;
4862                if(l == 3) l = 4;
4863                if((ranksize * l) <= 256) {
4864                        while((ranksize >>= 1)) reg += 0x10;
4865                }
4866
4867                if(!reg) continue;
4868
4869                SiS_SetRegANDOR(SISSR, 0x14, 0x0f, (reg & 0xf0));
4870                sisfb_post_xgi_delay(ivideo, 1);
4871
4872                if (sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize)) {
4873                        status = 0;
4874                        break;
4875                }
4876        }
4877
4878        iounmap(ivideo->video_vbase);
4879
4880        return status;
4881}
4882
4883static void sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4884{
4885        u8 v1, v2, v3;
4886        int index;
4887        static const u8 cs90[8 * 3] = {
4888                0x16, 0x01, 0x01,
4889                0x3e, 0x03, 0x01,
4890                0x7c, 0x08, 0x01,
4891                0x79, 0x06, 0x01,
4892                0x29, 0x01, 0x81,
4893                0x5c, 0x23, 0x01,
4894                0x5c, 0x23, 0x01,
4895                0x5c, 0x23, 0x01
4896        };
4897        static const u8 csb8[8 * 3] = {
4898                0x5c, 0x23, 0x01,
4899                0x29, 0x01, 0x01,
4900                0x7c, 0x08, 0x01,
4901                0x79, 0x06, 0x01,
4902                0x29, 0x01, 0x81,
4903                0x5c, 0x23, 0x01,
4904                0x5c, 0x23, 0x01,
4905                0x5c, 0x23, 0x01
4906        };
4907
4908        regb = 0;  /* ! */
4909
4910        index = regb * 3;
4911        v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4912        if(ivideo->haveXGIROM) {
4913                v1 = ivideo->bios_abase[0x90 + index];
4914                v2 = ivideo->bios_abase[0x90 + index + 1];
4915                v3 = ivideo->bios_abase[0x90 + index + 2];
4916        }
4917        SiS_SetReg(SISSR, 0x28, v1);
4918        SiS_SetReg(SISSR, 0x29, v2);
4919        SiS_SetReg(SISSR, 0x2a, v3);
4920        sisfb_post_xgi_delay(ivideo, 0x43);
4921        sisfb_post_xgi_delay(ivideo, 0x43);
4922        sisfb_post_xgi_delay(ivideo, 0x43);
4923        index = regb * 3;
4924        v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4925        if(ivideo->haveXGIROM) {
4926                v1 = ivideo->bios_abase[0xb8 + index];
4927                v2 = ivideo->bios_abase[0xb8 + index + 1];
4928                v3 = ivideo->bios_abase[0xb8 + index + 2];
4929        }
4930        SiS_SetReg(SISSR, 0x2e, v1);
4931        SiS_SetReg(SISSR, 0x2f, v2);
4932        SiS_SetReg(SISSR, 0x30, v3);
4933        sisfb_post_xgi_delay(ivideo, 0x43);
4934        sisfb_post_xgi_delay(ivideo, 0x43);
4935        sisfb_post_xgi_delay(ivideo, 0x43);
4936}
4937
4938static void sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo,
4939                                            u8 regb)
4940{
4941        unsigned char *bios = ivideo->bios_abase;
4942        u8 v1;
4943
4944        SiS_SetReg(SISSR, 0x28, 0x64);
4945        SiS_SetReg(SISSR, 0x29, 0x63);
4946        sisfb_post_xgi_delay(ivideo, 15);
4947        SiS_SetReg(SISSR, 0x18, 0x00);
4948        SiS_SetReg(SISSR, 0x19, 0x20);
4949        SiS_SetReg(SISSR, 0x16, 0x00);
4950        SiS_SetReg(SISSR, 0x16, 0x80);
4951        SiS_SetReg(SISSR, 0x18, 0xc5);
4952        SiS_SetReg(SISSR, 0x19, 0x23);
4953        SiS_SetReg(SISSR, 0x16, 0x00);
4954        SiS_SetReg(SISSR, 0x16, 0x80);
4955        sisfb_post_xgi_delay(ivideo, 1);
4956        SiS_SetReg(SISCR, 0x97, 0x11);
4957        sisfb_post_xgi_setclocks(ivideo, regb);
4958        sisfb_post_xgi_delay(ivideo, 0x46);
4959        SiS_SetReg(SISSR, 0x18, 0xc5);
4960        SiS_SetReg(SISSR, 0x19, 0x23);
4961        SiS_SetReg(SISSR, 0x16, 0x00);
4962        SiS_SetReg(SISSR, 0x16, 0x80);
4963        sisfb_post_xgi_delay(ivideo, 1);
4964        SiS_SetReg(SISSR, 0x1b, 0x04);
4965        sisfb_post_xgi_delay(ivideo, 1);
4966        SiS_SetReg(SISSR, 0x1b, 0x00);
4967        sisfb_post_xgi_delay(ivideo, 1);
4968        v1 = 0x31;
4969        if (ivideo->haveXGIROM) {
4970                v1 = bios[0xf0];
4971        }
4972        SiS_SetReg(SISSR, 0x18, v1);
4973        SiS_SetReg(SISSR, 0x19, 0x06);
4974        SiS_SetReg(SISSR, 0x16, 0x04);
4975        SiS_SetReg(SISSR, 0x16, 0x84);
4976        sisfb_post_xgi_delay(ivideo, 1);
4977}
4978
4979static void sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info *ivideo)
4980{
4981        sisfb_post_xgi_setclocks(ivideo, 1);
4982
4983        SiS_SetReg(SISCR, 0x97, 0x11);
4984        sisfb_post_xgi_delay(ivideo, 0x46);
4985
4986        SiS_SetReg(SISSR, 0x18, 0x00);  /* EMRS2 */
4987        SiS_SetReg(SISSR, 0x19, 0x80);
4988        SiS_SetReg(SISSR, 0x16, 0x05);
4989        SiS_SetReg(SISSR, 0x16, 0x85);
4990
4991        SiS_SetReg(SISSR, 0x18, 0x00);  /* EMRS3 */
4992        SiS_SetReg(SISSR, 0x19, 0xc0);
4993        SiS_SetReg(SISSR, 0x16, 0x05);
4994        SiS_SetReg(SISSR, 0x16, 0x85);
4995
4996        SiS_SetReg(SISSR, 0x18, 0x00);  /* EMRS1 */
4997        SiS_SetReg(SISSR, 0x19, 0x40);
4998        SiS_SetReg(SISSR, 0x16, 0x05);
4999        SiS_SetReg(SISSR, 0x16, 0x85);
5000
5001        SiS_SetReg(SISSR, 0x18, 0x42);  /* MRS1 */
5002        SiS_SetReg(SISSR, 0x19, 0x02);
5003        SiS_SetReg(SISSR, 0x16, 0x05);