linux/drivers/video/fbdev/savage/savagefb_driver.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/video/savagefb.c -- S3 Savage Framebuffer Driver
   3 *
   4 * Copyright (c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>
   5 *                          Sven Neumann <neo@directfb.org>
   6 *
   7 *
   8 * Card specific code is based on XFree86's savage driver.
   9 * Framebuffer framework code is based on code of cyber2000fb and tdfxfb.
  10 *
  11 * This file is subject to the terms and conditions of the GNU General
  12 * Public License.  See the file COPYING in the main directory of this
  13 * archive for more details.
  14 *
  15 * 0.4.0 (neo)
  16 *  - hardware accelerated clear and move
  17 *
  18 * 0.3.2 (dok)
  19 *  - wait for vertical retrace before writing to cr67
  20 *    at the beginning of savagefb_set_par
  21 *  - use synchronization registers cr23 and cr26
  22 *
  23 * 0.3.1 (dok)
  24 *  - reset 3D engine
  25 *  - don't return alpha bits for 32bit format
  26 *
  27 * 0.3.0 (dok)
  28 *  - added WaitIdle functions for all Savage types
  29 *  - do WaitIdle before mode switching
  30 *  - code cleanup
  31 *
  32 * 0.2.0 (dok)
  33 *  - first working version
  34 *
  35 *
  36 * TODO
  37 * - clock validations in decode_var
  38 *
  39 * BUGS
  40 * - white margin on bootup
  41 *
  42 */
  43
  44#include <linux/module.h>
  45#include <linux/kernel.h>
  46#include <linux/errno.h>
  47#include <linux/string.h>
  48#include <linux/mm.h>
  49#include <linux/slab.h>
  50#include <linux/delay.h>
  51#include <linux/fb.h>
  52#include <linux/pci.h>
  53#include <linux/init.h>
  54#include <linux/console.h>
  55
  56#include <asm/io.h>
  57#include <asm/irq.h>
  58
  59#include "savagefb.h"
  60
  61
  62#define SAVAGEFB_VERSION "0.4.0_2.6"
  63
  64/* --------------------------------------------------------------------- */
  65
  66
  67static char *mode_option = NULL;
  68
  69#ifdef MODULE
  70
  71MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>");
  72MODULE_LICENSE("GPL");
  73MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips");
  74
  75#endif
  76
  77
  78/* --------------------------------------------------------------------- */
  79
  80static void vgaHWSeqReset(struct savagefb_par *par, int start)
  81{
  82        if (start)
  83                VGAwSEQ(0x00, 0x01, par);       /* Synchronous Reset */
  84        else
  85                VGAwSEQ(0x00, 0x03, par);       /* End Reset */
  86}
  87
  88static void vgaHWProtect(struct savagefb_par *par, int on)
  89{
  90        unsigned char tmp;
  91
  92        if (on) {
  93                /*
  94                 * Turn off screen and disable sequencer.
  95                 */
  96                tmp = VGArSEQ(0x01, par);
  97
  98                vgaHWSeqReset(par, 1);          /* start synchronous reset */
  99                VGAwSEQ(0x01, tmp | 0x20, par);/* disable the display */
 100
 101                VGAenablePalette(par);
 102        } else {
 103                /*
 104                 * Reenable sequencer, then turn on screen.
 105                 */
 106
 107                tmp = VGArSEQ(0x01, par);
 108
 109                VGAwSEQ(0x01, tmp & ~0x20, par);/* reenable display */
 110                vgaHWSeqReset(par, 0);          /* clear synchronous reset */
 111
 112                VGAdisablePalette(par);
 113        }
 114}
 115
 116static void vgaHWRestore(struct savagefb_par  *par, struct savage_reg *reg)
 117{
 118        int i;
 119
 120        VGAwMISC(reg->MiscOutReg, par);
 121
 122        for (i = 1; i < 5; i++)
 123                VGAwSEQ(i, reg->Sequencer[i], par);
 124
 125        /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or
 126           CRTC[17] */
 127        VGAwCR(17, reg->CRTC[17] & ~0x80, par);
 128
 129        for (i = 0; i < 25; i++)
 130                VGAwCR(i, reg->CRTC[i], par);
 131
 132        for (i = 0; i < 9; i++)
 133                VGAwGR(i, reg->Graphics[i], par);
 134
 135        VGAenablePalette(par);
 136
 137        for (i = 0; i < 21; i++)
 138                VGAwATTR(i, reg->Attribute[i], par);
 139
 140        VGAdisablePalette(par);
 141}
 142
 143static void vgaHWInit(struct fb_var_screeninfo *var,
 144                      struct savagefb_par            *par,
 145                      struct xtimings                *timings,
 146                      struct savage_reg              *reg)
 147{
 148        reg->MiscOutReg = 0x23;
 149
 150        if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
 151                reg->MiscOutReg |= 0x40;
 152
 153        if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
 154                reg->MiscOutReg |= 0x80;
 155
 156        /*
 157         * Time Sequencer
 158         */
 159        reg->Sequencer[0x00] = 0x00;
 160        reg->Sequencer[0x01] = 0x01;
 161        reg->Sequencer[0x02] = 0x0F;
 162        reg->Sequencer[0x03] = 0x00;          /* Font select */
 163        reg->Sequencer[0x04] = 0x0E;          /* Misc */
 164
 165        /*
 166         * CRTC Controller
 167         */
 168        reg->CRTC[0x00] = (timings->HTotal >> 3) - 5;
 169        reg->CRTC[0x01] = (timings->HDisplay >> 3) - 1;
 170        reg->CRTC[0x02] = (timings->HSyncStart >> 3) - 1;
 171        reg->CRTC[0x03] = (((timings->HSyncEnd >> 3)  - 1) & 0x1f) | 0x80;
 172        reg->CRTC[0x04] = (timings->HSyncStart >> 3);
 173        reg->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) |
 174                (((timings->HSyncEnd >> 3)) & 0x1f);
 175        reg->CRTC[0x06] = (timings->VTotal - 2) & 0xFF;
 176        reg->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) |
 177                (((timings->VDisplay - 1) & 0x100) >> 7) |
 178                ((timings->VSyncStart & 0x100) >> 6) |
 179                (((timings->VSyncStart - 1) & 0x100) >> 5) |
 180                0x10 |
 181                (((timings->VTotal - 2) & 0x200) >> 4) |
 182                (((timings->VDisplay - 1) & 0x200) >> 3) |
 183                ((timings->VSyncStart & 0x200) >> 2);
 184        reg->CRTC[0x08] = 0x00;
 185        reg->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40;
 186
 187        if (timings->dblscan)
 188                reg->CRTC[0x09] |= 0x80;
 189
 190        reg->CRTC[0x0a] = 0x00;
 191        reg->CRTC[0x0b] = 0x00;
 192        reg->CRTC[0x0c] = 0x00;
 193        reg->CRTC[0x0d] = 0x00;
 194        reg->CRTC[0x0e] = 0x00;
 195        reg->CRTC[0x0f] = 0x00;
 196        reg->CRTC[0x10] = timings->VSyncStart & 0xff;
 197        reg->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20;
 198        reg->CRTC[0x12] = (timings->VDisplay - 1) & 0xff;
 199        reg->CRTC[0x13] = var->xres_virtual >> 4;
 200        reg->CRTC[0x14] = 0x00;
 201        reg->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff;
 202        reg->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff;
 203        reg->CRTC[0x17] = 0xc3;
 204        reg->CRTC[0x18] = 0xff;
 205
 206        /*
 207         * are these unnecessary?
 208         * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
 209         * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
 210         */
 211
 212        /*
 213         * Graphics Display Controller
 214         */
 215        reg->Graphics[0x00] = 0x00;
 216        reg->Graphics[0x01] = 0x00;
 217        reg->Graphics[0x02] = 0x00;
 218        reg->Graphics[0x03] = 0x00;
 219        reg->Graphics[0x04] = 0x00;
 220        reg->Graphics[0x05] = 0x40;
 221        reg->Graphics[0x06] = 0x05;   /* only map 64k VGA memory !!!! */
 222        reg->Graphics[0x07] = 0x0F;
 223        reg->Graphics[0x08] = 0xFF;
 224
 225
 226        reg->Attribute[0x00]  = 0x00; /* standard colormap translation */
 227        reg->Attribute[0x01]  = 0x01;
 228        reg->Attribute[0x02]  = 0x02;
 229        reg->Attribute[0x03]  = 0x03;
 230        reg->Attribute[0x04]  = 0x04;
 231        reg->Attribute[0x05]  = 0x05;
 232        reg->Attribute[0x06]  = 0x06;
 233        reg->Attribute[0x07]  = 0x07;
 234        reg->Attribute[0x08]  = 0x08;
 235        reg->Attribute[0x09]  = 0x09;
 236        reg->Attribute[0x0a] = 0x0A;
 237        reg->Attribute[0x0b] = 0x0B;
 238        reg->Attribute[0x0c] = 0x0C;
 239        reg->Attribute[0x0d] = 0x0D;
 240        reg->Attribute[0x0e] = 0x0E;
 241        reg->Attribute[0x0f] = 0x0F;
 242        reg->Attribute[0x10] = 0x41;
 243        reg->Attribute[0x11] = 0xFF;
 244        reg->Attribute[0x12] = 0x0F;
 245        reg->Attribute[0x13] = 0x00;
 246        reg->Attribute[0x14] = 0x00;
 247}
 248
 249/* -------------------- Hardware specific routines ------------------------- */
 250
 251/*
 252 * Hardware Acceleration for SavageFB
 253 */
 254
 255/* Wait for fifo space */
 256static void
 257savage3D_waitfifo(struct savagefb_par *par, int space)
 258{
 259        int slots = MAXFIFO - space;
 260
 261        while ((savage_in32(0x48C00, par) & 0x0000ffff) > slots);
 262}
 263
 264static void
 265savage4_waitfifo(struct savagefb_par *par, int space)
 266{
 267        int slots = MAXFIFO - space;
 268
 269        while ((savage_in32(0x48C60, par) & 0x001fffff) > slots);
 270}
 271
 272static void
 273savage2000_waitfifo(struct savagefb_par *par, int space)
 274{
 275        int slots = MAXFIFO - space;
 276
 277        while ((savage_in32(0x48C60, par) & 0x0000ffff) > slots);
 278}
 279
 280/* Wait for idle accelerator */
 281static void
 282savage3D_waitidle(struct savagefb_par *par)
 283{
 284        while ((savage_in32(0x48C00, par) & 0x0008ffff) != 0x80000);
 285}
 286
 287static void
 288savage4_waitidle(struct savagefb_par *par)
 289{
 290        while ((savage_in32(0x48C60, par) & 0x00a00000) != 0x00a00000);
 291}
 292
 293static void
 294savage2000_waitidle(struct savagefb_par *par)
 295{
 296        while ((savage_in32(0x48C60, par) & 0x009fffff));
 297}
 298
 299#ifdef CONFIG_FB_SAVAGE_ACCEL
 300static void
 301SavageSetup2DEngine(struct savagefb_par  *par)
 302{
 303        unsigned long GlobalBitmapDescriptor;
 304
 305        GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE;
 306        BCI_BD_SET_BPP(GlobalBitmapDescriptor, par->depth);
 307        BCI_BD_SET_STRIDE(GlobalBitmapDescriptor, par->vwidth);
 308
 309        switch(par->chip) {
 310        case S3_SAVAGE3D:
 311        case S3_SAVAGE_MX:
 312                /* Disable BCI */
 313                savage_out32(0x48C18, savage_in32(0x48C18, par) & 0x3FF0, par);
 314                /* Setup BCI command overflow buffer */
 315                savage_out32(0x48C14,
 316                             (par->cob_offset >> 11) | (par->cob_index << 29),
 317                             par);
 318                /* Program shadow status update. */
 319                savage_out32(0x48C10, 0x78207220, par);
 320                savage_out32(0x48C0C, 0, par);
 321                /* Enable BCI and command overflow buffer */
 322                savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x0C, par);
 323                break;
 324        case S3_SAVAGE4:
 325        case S3_TWISTER:
 326        case S3_PROSAVAGE:
 327        case S3_PROSAVAGEDDR:
 328        case S3_SUPERSAVAGE:
 329                /* Disable BCI */
 330                savage_out32(0x48C18, savage_in32(0x48C18, par) & 0x3FF0, par);
 331                /* Program shadow status update */
 332                savage_out32(0x48C10, 0x00700040, par);
 333                savage_out32(0x48C0C, 0, par);
 334                /* Enable BCI without the COB */
 335                savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x08, par);
 336                break;
 337        case S3_SAVAGE2000:
 338                /* Disable BCI */
 339                savage_out32(0x48C18, 0, par);
 340                /* Setup BCI command overflow buffer */
 341                savage_out32(0x48C18,
 342                             (par->cob_offset >> 7) | (par->cob_index),
 343                             par);
 344                /* Disable shadow status update */
 345                savage_out32(0x48A30, 0, par);
 346                /* Enable BCI and command overflow buffer */
 347                savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x00280000,
 348                             par);
 349                break;
 350            default:
 351                break;
 352        }
 353        /* Turn on 16-bit register access. */
 354        vga_out8(0x3d4, 0x31, par);
 355        vga_out8(0x3d5, 0x0c, par);
 356
 357        /* Set stride to use GBD. */
 358        vga_out8(0x3d4, 0x50, par);
 359        vga_out8(0x3d5, vga_in8(0x3d5, par) | 0xC1, par);
 360
 361        /* Enable 2D engine. */
 362        vga_out8(0x3d4, 0x40, par);
 363        vga_out8(0x3d5, 0x01, par);
 364
 365        savage_out32(MONO_PAT_0, ~0, par);
 366        savage_out32(MONO_PAT_1, ~0, par);
 367
 368        /* Setup plane masks */
 369        savage_out32(0x8128, ~0, par); /* enable all write planes */
 370        savage_out32(0x812C, ~0, par); /* enable all read planes */
 371        savage_out16(0x8134, 0x27, par);
 372        savage_out16(0x8136, 0x07, par);
 373
 374        /* Now set the GBD */
 375        par->bci_ptr = 0;
 376        par->SavageWaitFifo(par, 4);
 377
 378        BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD1);
 379        BCI_SEND(0);
 380        BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD2);
 381        BCI_SEND(GlobalBitmapDescriptor);
 382
 383        /*
 384         * I don't know why, sending this twice fixes the initial black screen,
 385         * prevents X from crashing at least in Toshiba laptops with SavageIX.
 386         * --Tony
 387         */
 388        par->bci_ptr = 0;
 389        par->SavageWaitFifo(par, 4);
 390
 391        BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD1);
 392        BCI_SEND(0);
 393        BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD2);
 394        BCI_SEND(GlobalBitmapDescriptor);
 395}
 396
 397static void savagefb_set_clip(struct fb_info *info)
 398{
 399        struct savagefb_par *par = info->par;
 400        int cmd;
 401
 402        cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW;
 403        par->bci_ptr = 0;
 404        par->SavageWaitFifo(par,3);
 405        BCI_SEND(cmd);
 406        BCI_SEND(BCI_CLIP_TL(0, 0));
 407        BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff));
 408}
 409#else
 410static void SavageSetup2DEngine(struct savagefb_par  *par) {}
 411
 412#endif
 413
 414static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
 415                            int min_n2, int max_n2, long freq_min,
 416                            long freq_max, unsigned int *mdiv,
 417                            unsigned int *ndiv, unsigned int *r)
 418{
 419        long diff, best_diff;
 420        unsigned int m;
 421        unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2;
 422
 423        if (freq < freq_min / (1 << max_n2)) {
 424                printk(KERN_ERR "invalid frequency %ld Khz\n", freq);
 425                freq = freq_min / (1 << max_n2);
 426        }
 427        if (freq > freq_max / (1 << min_n2)) {
 428                printk(KERN_ERR "invalid frequency %ld Khz\n", freq);
 429                freq = freq_max / (1 << min_n2);
 430        }
 431
 432        /* work out suitable timings */
 433        best_diff = freq;
 434
 435        for (n2=min_n2; n2<=max_n2; n2++) {
 436                for (n1=min_n1+2; n1<=max_n1+2; n1++) {
 437                        m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) /
 438                                BASE_FREQ;
 439                        if (m < min_m+2 || m > 127+2)
 440                                continue;
 441                        if ((m * BASE_FREQ >= freq_min * n1) &&
 442                            (m * BASE_FREQ <= freq_max * n1)) {
 443                                diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
 444                                if (diff < 0)
 445                                        diff = -diff;
 446                                if (diff < best_diff) {
 447                                        best_diff = diff;
 448                                        best_m = m;
 449                                        best_n1 = n1;
 450                                        best_n2 = n2;
 451                                }
 452                        }
 453                }
 454        }
 455
 456        *ndiv = best_n1 - 2;
 457        *r = best_n2;
 458        *mdiv = best_m - 2;
 459}
 460
 461static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1,
 462                             int min_n2, int max_n2, long freq_min,
 463                             long freq_max, unsigned char *mdiv,
 464                             unsigned char *ndiv)
 465{
 466        long diff, best_diff;
 467        unsigned int m;
 468        unsigned char n1, n2;
 469        unsigned char best_n1 = 16+2, best_n2 = 2, best_m = 125+2;
 470
 471        best_diff = freq;
 472
 473        for (n2 = min_n2; n2 <= max_n2; n2++) {
 474                for (n1 = min_n1+2; n1 <= max_n1+2; n1++) {
 475                        m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) /
 476                                BASE_FREQ;
 477                        if (m < min_m + 2 || m > 127+2)
 478                                continue;
 479                        if ((m * BASE_FREQ >= freq_min * n1) &&
 480                            (m * BASE_FREQ <= freq_max * n1)) {
 481                                diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
 482                                if (diff < 0)
 483                                        diff = -diff;
 484                                if (diff < best_diff) {
 485                                        best_diff = diff;
 486                                        best_m = m;
 487                                        best_n1 = n1;
 488                                        best_n2 = n2;
 489                                }
 490                        }
 491                }
 492        }
 493
 494        if (max_n1 == 63)
 495                *ndiv = (best_n1 - 2) | (best_n2 << 6);
 496        else
 497                *ndiv = (best_n1 - 2) | (best_n2 << 5);
 498
 499        *mdiv = best_m - 2;
 500
 501        return 0;
 502}
 503
 504#ifdef SAVAGEFB_DEBUG
 505/* This function is used to debug, it prints out the contents of s3 regs */
 506
 507static void SavagePrintRegs(struct savagefb_par *par)
 508{
 509        unsigned char i;
 510        int vgaCRIndex = 0x3d4;
 511        int vgaCRReg = 0x3d5;
 512
 513        printk(KERN_DEBUG "SR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE "
 514               "xF");
 515
 516        for (i = 0; i < 0x70; i++) {
 517                if (!(i % 16))
 518                        printk(KERN_DEBUG "\nSR%xx ", i >> 4);
 519                vga_out8(0x3c4, i, par);
 520                printk(KERN_DEBUG " %02x", vga_in8(0x3c5, par));
 521        }
 522
 523        printk(KERN_DEBUG "\n\nCR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC "
 524               "xD xE xF");
 525
 526        for (i = 0; i < 0xB7; i++) {
 527                if (!(i % 16))
 528                        printk(KERN_DEBUG "\nCR%xx ", i >> 4);
 529                vga_out8(vgaCRIndex, i, par);
 530                printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg, par));
 531        }
 532
 533        printk(KERN_DEBUG "\n\n");
 534}
 535#endif
 536
 537/* --------------------------------------------------------------------- */
 538
 539static void savage_get_default_par(struct savagefb_par *par, struct savage_reg *reg)
 540{
 541        unsigned char cr3a, cr53, cr66;
 542
 543        vga_out16(0x3d4, 0x4838, par);
 544        vga_out16(0x3d4, 0xa039, par);
 545        vga_out16(0x3c4, 0x0608, par);
 546
 547        vga_out8(0x3d4, 0x66, par);
 548        cr66 = vga_in8(0x3d5, par);
 549        vga_out8(0x3d5, cr66 | 0x80, par);
 550        vga_out8(0x3d4, 0x3a, par);
 551        cr3a = vga_in8(0x3d5, par);
 552        vga_out8(0x3d5, cr3a | 0x80, par);
 553        vga_out8(0x3d4, 0x53, par);
 554        cr53 = vga_in8(0x3d5, par);
 555        vga_out8(0x3d5, cr53 & 0x7f, par);
 556
 557        vga_out8(0x3d4, 0x66, par);
 558        vga_out8(0x3d5, cr66, par);
 559        vga_out8(0x3d4, 0x3a, par);
 560        vga_out8(0x3d5, cr3a, par);
 561
 562        vga_out8(0x3d4, 0x66, par);
 563        vga_out8(0x3d5, cr66, par);
 564        vga_out8(0x3d4, 0x3a, par);
 565        vga_out8(0x3d5, cr3a, par);
 566
 567        /* unlock extended seq regs */
 568        vga_out8(0x3c4, 0x08, par);
 569        reg->SR08 = vga_in8(0x3c5, par);
 570        vga_out8(0x3c5, 0x06, par);
 571
 572        /* now save all the extended regs we need */
 573        vga_out8(0x3d4, 0x31, par);
 574        reg->CR31 = vga_in8(0x3d5, par);
 575        vga_out8(0x3d4, 0x32, par);
 576        reg->CR32 = vga_in8(0x3d5, par);
 577        vga_out8(0x3d4, 0x34, par);
 578        reg->CR34 = vga_in8(0x3d5, par);
 579        vga_out8(0x3d4, 0x36, par);
 580        reg->CR36 = vga_in8(0x3d5, par);
 581        vga_out8(0x3d4, 0x3a, par);
 582        reg->CR3A = vga_in8(0x3d5, par);
 583        vga_out8(0x3d4, 0x40, par);
 584        reg->CR40 = vga_in8(0x3d5, par);
 585        vga_out8(0x3d4, 0x42, par);
 586        reg->CR42 = vga_in8(0x3d5, par);
 587        vga_out8(0x3d4, 0x45, par);
 588        reg->CR45 = vga_in8(0x3d5, par);
 589        vga_out8(0x3d4, 0x50, par);
 590        reg->CR50 = vga_in8(0x3d5, par);
 591        vga_out8(0x3d4, 0x51, par);
 592        reg->CR51 = vga_in8(0x3d5, par);
 593        vga_out8(0x3d4, 0x53, par);
 594        reg->CR53 = vga_in8(0x3d5, par);
 595        vga_out8(0x3d4, 0x58, par);
 596        reg->CR58 = vga_in8(0x3d5, par);
 597        vga_out8(0x3d4, 0x60, par);
 598        reg->CR60 = vga_in8(0x3d5, par);
 599        vga_out8(0x3d4, 0x66, par);
 600        reg->CR66 = vga_in8(0x3d5, par);
 601        vga_out8(0x3d4, 0x67, par);
 602        reg->CR67 = vga_in8(0x3d5, par);
 603        vga_out8(0x3d4, 0x68, par);
 604        reg->CR68 = vga_in8(0x3d5, par);
 605        vga_out8(0x3d4, 0x69, par);
 606        reg->CR69 = vga_in8(0x3d5, par);
 607        vga_out8(0x3d4, 0x6f, par);
 608        reg->CR6F = vga_in8(0x3d5, par);
 609
 610        vga_out8(0x3d4, 0x33, par);
 611        reg->CR33 = vga_in8(0x3d5, par);
 612        vga_out8(0x3d4, 0x86, par);
 613        reg->CR86 = vga_in8(0x3d5, par);
 614        vga_out8(0x3d4, 0x88, par);
 615        reg->CR88 = vga_in8(0x3d5, par);
 616        vga_out8(0x3d4, 0x90, par);
 617        reg->CR90 = vga_in8(0x3d5, par);
 618        vga_out8(0x3d4, 0x91, par);
 619        reg->CR91 = vga_in8(0x3d5, par);
 620        vga_out8(0x3d4, 0xb0, par);
 621        reg->CRB0 = vga_in8(0x3d5, par) | 0x80;
 622
 623        /* extended mode timing regs */
 624        vga_out8(0x3d4, 0x3b, par);
 625        reg->CR3B = vga_in8(0x3d5, par);
 626        vga_out8(0x3d4, 0x3c, par);
 627        reg->CR3C = vga_in8(0x3d5, par);
 628        vga_out8(0x3d4, 0x43, par);
 629        reg->CR43 = vga_in8(0x3d5, par);
 630        vga_out8(0x3d4, 0x5d, par);
 631        reg->CR5D = vga_in8(0x3d5, par);
 632        vga_out8(0x3d4, 0x5e, par);
 633        reg->CR5E = vga_in8(0x3d5, par);
 634        vga_out8(0x3d4, 0x65, par);
 635        reg->CR65 = vga_in8(0x3d5, par);
 636
 637        /* save seq extended regs for DCLK PLL programming */
 638        vga_out8(0x3c4, 0x0e, par);
 639        reg->SR0E = vga_in8(0x3c5, par);
 640        vga_out8(0x3c4, 0x0f, par);
 641        reg->SR0F = vga_in8(0x3c5, par);
 642        vga_out8(0x3c4, 0x10, par);
 643        reg->SR10 = vga_in8(0x3c5, par);
 644        vga_out8(0x3c4, 0x11, par);
 645        reg->SR11 = vga_in8(0x3c5, par);
 646        vga_out8(0x3c4, 0x12, par);
 647        reg->SR12 = vga_in8(0x3c5, par);
 648        vga_out8(0x3c4, 0x13, par);
 649        reg->SR13 = vga_in8(0x3c5, par);
 650        vga_out8(0x3c4, 0x29, par);
 651        reg->SR29 = vga_in8(0x3c5, par);
 652
 653        vga_out8(0x3c4, 0x15, par);
 654        reg->SR15 = vga_in8(0x3c5, par);
 655        vga_out8(0x3c4, 0x30, par);
 656        reg->SR30 = vga_in8(0x3c5, par);
 657        vga_out8(0x3c4, 0x18, par);
 658        reg->SR18 = vga_in8(0x3c5, par);
 659
 660        /* Save flat panel expansion registers. */
 661        if (par->chip == S3_SAVAGE_MX) {
 662                int i;
 663
 664                for (i = 0; i < 8; i++) {
 665                        vga_out8(0x3c4, 0x54+i, par);
 666                        reg->SR54[i] = vga_in8(0x3c5, par);
 667                }
 668        }
 669
 670        vga_out8(0x3d4, 0x66, par);
 671        cr66 = vga_in8(0x3d5, par);
 672        vga_out8(0x3d5, cr66 | 0x80, par);
 673        vga_out8(0x3d4, 0x3a, par);
 674        cr3a = vga_in8(0x3d5, par);
 675        vga_out8(0x3d5, cr3a | 0x80, par);
 676
 677        /* now save MIU regs */
 678        if (par->chip != S3_SAVAGE_MX) {
 679                reg->MMPR0 = savage_in32(FIFO_CONTROL_REG, par);
 680                reg->MMPR1 = savage_in32(MIU_CONTROL_REG, par);
 681                reg->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG, par);
 682                reg->MMPR3 = savage_in32(MISC_TIMEOUT_REG, par);
 683        }
 684
 685        vga_out8(0x3d4, 0x3a, par);
 686        vga_out8(0x3d5, cr3a, par);
 687        vga_out8(0x3d4, 0x66, par);
 688        vga_out8(0x3d5, cr66, par);
 689}
 690
 691static void savage_set_default_par(struct savagefb_par *par,
 692                                struct savage_reg *reg)
 693{
 694        unsigned char cr3a, cr53, cr66;
 695
 696        vga_out16(0x3d4, 0x4838, par);
 697        vga_out16(0x3d4, 0xa039, par);
 698        vga_out16(0x3c4, 0x0608, par);
 699
 700        vga_out8(0x3d4, 0x66, par);
 701        cr66 = vga_in8(0x3d5, par);
 702        vga_out8(0x3d5, cr66 | 0x80, par);
 703        vga_out8(0x3d4, 0x3a, par);
 704        cr3a = vga_in8(0x3d5, par);
 705        vga_out8(0x3d5, cr3a | 0x80, par);
 706        vga_out8(0x3d4, 0x53, par);
 707        cr53 = vga_in8(0x3d5, par);
 708        vga_out8(0x3d5, cr53 & 0x7f, par);
 709
 710        vga_out8(0x3d4, 0x66, par);
 711        vga_out8(0x3d5, cr66, par);
 712        vga_out8(0x3d4, 0x3a, par);
 713        vga_out8(0x3d5, cr3a, par);
 714
 715        vga_out8(0x3d4, 0x66, par);
 716        vga_out8(0x3d5, cr66, par);
 717        vga_out8(0x3d4, 0x3a, par);
 718        vga_out8(0x3d5, cr3a, par);
 719
 720        /* unlock extended seq regs */
 721        vga_out8(0x3c4, 0x08, par);
 722        vga_out8(0x3c5, reg->SR08, par);
 723        vga_out8(0x3c5, 0x06, par);
 724
 725        /* now restore all the extended regs we need */
 726        vga_out8(0x3d4, 0x31, par);
 727        vga_out8(0x3d5, reg->CR31, par);
 728        vga_out8(0x3d4, 0x32, par);
 729        vga_out8(0x3d5, reg->CR32, par);
 730        vga_out8(0x3d4, 0x34, par);
 731        vga_out8(0x3d5, reg->CR34, par);
 732        vga_out8(0x3d4, 0x36, par);
 733        vga_out8(0x3d5,reg->CR36, par);
 734        vga_out8(0x3d4, 0x3a, par);
 735        vga_out8(0x3d5, reg->CR3A, par);
 736        vga_out8(0x3d4, 0x40, par);
 737        vga_out8(0x3d5, reg->CR40, par);
 738        vga_out8(0x3d4, 0x42, par);
 739        vga_out8(0x3d5, reg->CR42, par);
 740        vga_out8(0x3d4, 0x45, par);
 741        vga_out8(0x3d5, reg->CR45, par);
 742        vga_out8(0x3d4, 0x50, par);
 743        vga_out8(0x3d5, reg->CR50, par);
 744        vga_out8(0x3d4, 0x51, par);
 745        vga_out8(0x3d5, reg->CR51, par);
 746        vga_out8(0x3d4, 0x53, par);
 747        vga_out8(0x3d5, reg->CR53, par);
 748        vga_out8(0x3d4, 0x58, par);
 749        vga_out8(0x3d5, reg->CR58, par);
 750        vga_out8(0x3d4, 0x60, par);
 751        vga_out8(0x3d5, reg->CR60, par);
 752        vga_out8(0x3d4, 0x66, par);
 753        vga_out8(0x3d5, reg->CR66, par);
 754        vga_out8(0x3d4, 0x67, par);
 755        vga_out8(0x3d5, reg->CR67, par);
 756        vga_out8(0x3d4, 0x68, par);
 757        vga_out8(0x3d5, reg->CR68, par);
 758        vga_out8(0x3d4, 0x69, par);
 759        vga_out8(0x3d5, reg->CR69, par);
 760        vga_out8(0x3d4, 0x6f, par);
 761        vga_out8(0x3d5, reg->CR6F, par);
 762
 763        vga_out8(0x3d4, 0x33, par);
 764        vga_out8(0x3d5, reg->CR33, par);
 765        vga_out8(0x3d4, 0x86, par);
 766        vga_out8(0x3d5, reg->CR86, par);
 767        vga_out8(0x3d4, 0x88, par);
 768        vga_out8(0x3d5, reg->CR88, par);
 769        vga_out8(0x3d4, 0x90, par);
 770        vga_out8(0x3d5, reg->CR90, par);
 771        vga_out8(0x3d4, 0x91, par);
 772        vga_out8(0x3d5, reg->CR91, par);
 773        vga_out8(0x3d4, 0xb0, par);
 774        vga_out8(0x3d5, reg->CRB0, par);
 775
 776        /* extended mode timing regs */
 777        vga_out8(0x3d4, 0x3b, par);
 778        vga_out8(0x3d5, reg->CR3B, par);
 779        vga_out8(0x3d4, 0x3c, par);
 780        vga_out8(0x3d5, reg->CR3C, par);
 781        vga_out8(0x3d4, 0x43, par);
 782        vga_out8(0x3d5, reg->CR43, par);
 783        vga_out8(0x3d4, 0x5d, par);
 784        vga_out8(0x3d5, reg->CR5D, par);
 785        vga_out8(0x3d4, 0x5e, par);
 786        vga_out8(0x3d5, reg->CR5E, par);
 787        vga_out8(0x3d4, 0x65, par);
 788        vga_out8(0x3d5, reg->CR65, par);
 789
 790        /* save seq extended regs for DCLK PLL programming */
 791        vga_out8(0x3c4, 0x0e, par);
 792        vga_out8(0x3c5, reg->SR0E, par);
 793        vga_out8(0x3c4, 0x0f, par);
 794        vga_out8(0x3c5, reg->SR0F, par);
 795        vga_out8(0x3c4, 0x10, par);
 796        vga_out8(0x3c5, reg->SR10, par);
 797        vga_out8(0x3c4, 0x11, par);
 798        vga_out8(0x3c5, reg->SR11, par);
 799        vga_out8(0x3c4, 0x12, par);
 800        vga_out8(0x3c5, reg->SR12, par);
 801        vga_out8(0x3c4, 0x13, par);
 802        vga_out8(0x3c5, reg->SR13, par);
 803        vga_out8(0x3c4, 0x29, par);
 804        vga_out8(0x3c5, reg->SR29, par);
 805
 806        vga_out8(0x3c4, 0x15, par);
 807        vga_out8(0x3c5, reg->SR15, par);
 808        vga_out8(0x3c4, 0x30, par);
 809        vga_out8(0x3c5, reg->SR30, par);
 810        vga_out8(0x3c4, 0x18, par);
 811        vga_out8(0x3c5, reg->SR18, par);
 812
 813        /* Save flat panel expansion registers. */
 814        if (par->chip == S3_SAVAGE_MX) {
 815                int i;
 816
 817                for (i = 0; i < 8; i++) {
 818                        vga_out8(0x3c4, 0x54+i, par);
 819                        vga_out8(0x3c5, reg->SR54[i], par);
 820                }
 821        }
 822
 823        vga_out8(0x3d4, 0x66, par);
 824        cr66 = vga_in8(0x3d5, par);
 825        vga_out8(0x3d5, cr66 | 0x80, par);
 826        vga_out8(0x3d4, 0x3a, par);
 827        cr3a = vga_in8(0x3d5, par);
 828        vga_out8(0x3d5, cr3a | 0x80, par);
 829
 830        /* now save MIU regs */
 831        if (par->chip != S3_SAVAGE_MX) {
 832                savage_out32(FIFO_CONTROL_REG, reg->MMPR0, par);
 833                savage_out32(MIU_CONTROL_REG, reg->MMPR1, par);
 834                savage_out32(STREAMS_TIMEOUT_REG, reg->MMPR2, par);
 835                savage_out32(MISC_TIMEOUT_REG, reg->MMPR3, par);
 836        }
 837
 838        vga_out8(0x3d4, 0x3a, par);
 839        vga_out8(0x3d5, cr3a, par);
 840        vga_out8(0x3d4, 0x66, par);
 841        vga_out8(0x3d5, cr66, par);
 842}
 843
 844static void savage_update_var(struct fb_var_screeninfo *var,
 845                              const struct fb_videomode *modedb)
 846{
 847        var->xres = var->xres_virtual = modedb->xres;
 848        var->yres = modedb->yres;
 849        if (var->yres_virtual < var->yres)
 850            var->yres_virtual = var->yres;
 851        var->xoffset = var->yoffset = 0;
 852        var->pixclock = modedb->pixclock;
 853        var->left_margin = modedb->left_margin;
 854        var->right_margin = modedb->right_margin;
 855        var->upper_margin = modedb->upper_margin;
 856        var->lower_margin = modedb->lower_margin;
 857        var->hsync_len = modedb->hsync_len;
 858        var->vsync_len = modedb->vsync_len;
 859        var->sync = modedb->sync;
 860        var->vmode = modedb->vmode;
 861}
 862
 863static int savagefb_check_var(struct fb_var_screeninfo   *var,
 864                              struct fb_info *info)
 865{
 866        struct savagefb_par *par = info->par;
 867        int memlen, vramlen, mode_valid = 0;
 868
 869        DBG("savagefb_check_var");
 870
 871        var->transp.offset = 0;
 872        var->transp.length = 0;
 873        switch (var->bits_per_pixel) {
 874        case 8:
 875                var->red.offset = var->green.offset =
 876                        var->blue.offset = 0;
 877                var->red.length = var->green.length =
 878                        var->blue.length = var->bits_per_pixel;
 879                break;
 880        case 16:
 881                var->red.offset = 11;
 882                var->red.length = 5;
 883                var->green.offset = 5;
 884                var->green.length = 6;
 885                var->blue.offset = 0;
 886                var->blue.length = 5;
 887                break;
 888        case 32:
 889                var->transp.offset = 24;
 890                var->transp.length = 8;
 891                var->red.offset = 16;
 892                var->red.length = 8;
 893                var->green.offset = 8;
 894                var->green.length = 8;
 895                var->blue.offset = 0;
 896                var->blue.length = 8;
 897                break;
 898
 899        default:
 900                return -EINVAL;
 901        }
 902
 903        if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
 904            !info->monspecs.dclkmax || !fb_validate_mode(var, info))
 905                mode_valid = 1;
 906
 907        /* calculate modeline if supported by monitor */
 908        if (!mode_valid && info->monspecs.gtf) {
 909                if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
 910                        mode_valid = 1;
 911        }
 912
 913        if (!mode_valid) {
 914                const struct fb_videomode *mode;
 915
 916                mode = fb_find_best_mode(var, &info->modelist);
 917                if (mode) {
 918                        savage_update_var(var, mode);
 919                        mode_valid = 1;
 920                }
 921        }
 922
 923        if (!mode_valid && info->monspecs.modedb_len)
 924                return -EINVAL;
 925
 926        /* Is the mode larger than the LCD panel? */
 927        if (par->SavagePanelWidth &&
 928            (var->xres > par->SavagePanelWidth ||
 929             var->yres > par->SavagePanelHeight)) {
 930                printk(KERN_INFO "Mode (%dx%d) larger than the LCD panel "
 931                       "(%dx%d)\n", var->xres,  var->yres,
 932                       par->SavagePanelWidth,
 933                       par->SavagePanelHeight);
 934                return -1;
 935        }
 936
 937        if (var->yres_virtual < var->yres)
 938                var->yres_virtual = var->yres;
 939        if (var->xres_virtual < var->xres)
 940                var->xres_virtual = var->xres;
 941
 942        vramlen = info->fix.smem_len;
 943
 944        memlen = var->xres_virtual * var->bits_per_pixel *
 945                var->yres_virtual / 8;
 946        if (memlen > vramlen) {
 947                var->yres_virtual = vramlen * 8 /
 948                        (var->xres_virtual * var->bits_per_pixel);
 949                memlen = var->xres_virtual * var->bits_per_pixel *
 950                        var->yres_virtual / 8;
 951        }
 952
 953        /* we must round yres/xres down, we already rounded y/xres_virtual up
 954           if it was possible. We should return -EINVAL, but I disagree */
 955        if (var->yres_virtual < var->yres)
 956                var->yres = var->yres_virtual;
 957        if (var->xres_virtual < var->xres)
 958                var->xres = var->xres_virtual;
 959        if (var->xoffset + var->xres > var->xres_virtual)
 960                var->xoffset = var->xres_virtual - var->xres;
 961        if (var->yoffset + var->yres > var->yres_virtual)
 962                var->yoffset = var->yres_virtual - var->yres;
 963
 964        return 0;
 965}
 966
 967
 968static int savagefb_decode_var(struct fb_var_screeninfo   *var,
 969                               struct savagefb_par        *par,
 970                               struct savage_reg          *reg)
 971{
 972        struct xtimings timings;
 973        int width, dclk, i, j; /*, refresh; */
 974        unsigned int m, n, r;
 975        unsigned char tmp = 0;
 976        unsigned int pixclock = var->pixclock;
 977
 978        DBG("savagefb_decode_var");
 979
 980        memset(&timings, 0, sizeof(timings));
 981
 982        if (!pixclock) pixclock = 10000;        /* 10ns = 100MHz */
 983        timings.Clock = 1000000000 / pixclock;
 984        if (timings.Clock < 1) timings.Clock = 1;
 985        timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
 986        timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
 987        timings.HDisplay = var->xres;
 988        timings.HSyncStart = timings.HDisplay + var->right_margin;
 989        timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
 990        timings.HTotal = timings.HSyncEnd + var->left_margin;
 991        timings.VDisplay = var->yres;
 992        timings.VSyncStart = timings.VDisplay + var->lower_margin;
 993        timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
 994        timings.VTotal = timings.VSyncEnd + var->upper_margin;
 995        timings.sync = var->sync;
 996
 997
 998        par->depth  = var->bits_per_pixel;
 999        par->vwidth = var->xres_virtual;
1000
1001        if (var->bits_per_pixel == 16  &&  par->chip == S3_SAVAGE3D) {
1002                timings.HDisplay *= 2;
1003                timings.HSyncStart *= 2;
1004                timings.HSyncEnd *= 2;
1005                timings.HTotal *= 2;
1006        }
1007
1008        /*
1009         * This will allocate the datastructure and initialize all of the
1010         * generic VGA registers.
1011         */
1012        vgaHWInit(var, par, &timings, reg);
1013
1014        /* We need to set CR67 whether or not we use the BIOS. */
1015
1016        dclk = timings.Clock;
1017        reg->CR67 = 0x00;
1018
1019        switch(var->bits_per_pixel) {
1020        case 8:
1021                if ((par->chip == S3_SAVAGE2000) && (dclk >= 230000))
1022                        reg->CR67 = 0x10;       /* 8bpp, 2 pixels/clock */
1023                else
1024                        reg->CR67 = 0x00;       /* 8bpp, 1 pixel/clock */
1025                break;
1026        case 15:
1027                if (S3_SAVAGE_MOBILE_SERIES(par->chip) ||
1028                    ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)))
1029                        reg->CR67 = 0x30;       /* 15bpp, 2 pixel/clock */
1030                else
1031                        reg->CR67 = 0x20;       /* 15bpp, 1 pixels/clock */
1032                break;
1033        case 16:
1034                if (S3_SAVAGE_MOBILE_SERIES(par->chip) ||
1035                   ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)))
1036                        reg->CR67 = 0x50;       /* 16bpp, 2 pixel/clock */
1037                else
1038                        reg->CR67 = 0x40;       /* 16bpp, 1 pixels/clock */
1039                break;
1040        case 24:
1041                reg->CR67 = 0x70;
1042                break;
1043        case 32:
1044                reg->CR67 = 0xd0;
1045                break;
1046        }
1047
1048        /*
1049         * Either BIOS use is disabled, or we failed to find a suitable
1050         * match.  Fall back to traditional register-crunching.
1051         */
1052
1053        vga_out8(0x3d4, 0x3a, par);
1054        tmp = vga_in8(0x3d5, par);
1055        if (1 /*FIXME:psav->pci_burst*/)
1056                reg->CR3A = (tmp & 0x7f) | 0x15;
1057        else
1058                reg->CR3A = tmp | 0x95;
1059
1060        reg->CR53 = 0x00;
1061        reg->CR31 = 0x8c;
1062        reg->CR66 = 0x89;
1063
1064        vga_out8(0x3d4, 0x58, par);
1065        reg->CR58 = vga_in8(0x3d5, par) & 0x80;
1066        reg->CR58 |= 0x13;
1067
1068        reg->SR15 = 0x03 | 0x80;
1069        reg->SR18 = 0x00;
1070        reg->CR43 = reg->CR45 = reg->CR65 = 0x00;
1071
1072        vga_out8(0x3d4, 0x40, par);
1073        reg->CR40 = vga_in8(0x3d5, par) & ~0x01;
1074
1075        reg->MMPR0 = 0x010400;
1076        reg->MMPR1 = 0x00;
1077        reg->MMPR2 = 0x0808;
1078        reg->MMPR3 = 0x08080810;
1079
1080        SavageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);
1081        /* m = 107; n = 4; r = 2; */
1082
1083        if (par->MCLK <= 0) {
1084                reg->SR10 = 255;
1085                reg->SR11 = 255;
1086        } else {
1087                common_calc_clock(par->MCLK, 1, 1, 31, 0, 3, 135000, 270000,
1088                                   &reg->SR11, &reg->SR10);
1089                /*      reg->SR10 = 80; // MCLK == 286000 */
1090                /*      reg->SR11 = 125; */
1091        }
1092
1093        reg->SR12 = (r << 6) | (n & 0x3f);
1094        reg->SR13 = m & 0xff;
1095        reg->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
1096
1097        if (var->bits_per_pixel < 24)
1098                reg->MMPR0 -= 0x8000;
1099        else
1100                reg->MMPR0 -= 0x4000;
1101
1102        if (timings.interlaced)
1103                reg->CR42 = 0x20;
1104        else
1105                reg->CR42 = 0x00;
1106
1107        reg->CR34 = 0x10; /* display fifo */
1108
1109        i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) |
1110                ((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) |
1111                ((((timings.HSyncStart >> 3) - 1) & 0x100) >> 6) |
1112                ((timings.HSyncStart & 0x800) >> 7);
1113
1114        if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 64)
1115                i |= 0x08;
1116        if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32)
1117                i |= 0x20;
1118
1119        j = (reg->CRTC[0] + ((i & 0x01) << 8) +
1120             reg->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
1121
1122        if (j - (reg->CRTC[4] + ((i & 0x10) << 4)) < 4) {
1123                if (reg->CRTC[4] + ((i & 0x10) << 4) + 4 <=
1124                    reg->CRTC[0] + ((i & 0x01) << 8))
1125                        j = reg->CRTC[4] + ((i & 0x10) << 4) + 4;
1126                else
1127                        j = reg->CRTC[0] + ((i & 0x01) << 8) + 1;
1128        }
1129
1130        reg->CR3B = j & 0xff;
1131        i |= (j & 0x100) >> 2;
1132        reg->CR3C = (reg->CRTC[0] + ((i & 0x01) << 8)) / 2;
1133        reg->CR5D = i;
1134        reg->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) |
1135                (((timings.VDisplay - 1) & 0x400) >> 9) |
1136                (((timings.VSyncStart) & 0x400) >> 8) |
1137                (((timings.VSyncStart) & 0x400) >> 6) | 0x40;
1138        width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3;
1139        reg->CR91 = reg->CRTC[19] = 0xff & width;
1140        reg->CR51 = (0x300 & width) >> 4;
1141        reg->CR90 = 0x80 | (width >> 8);
1142        reg->MiscOutReg |= 0x0c;
1143
1144        /* Set frame buffer description. */
1145
1146        if (var->bits_per_pixel <= 8)
1147                reg->CR50 = 0;
1148        else if (var->bits_per_pixel <= 16)
1149                reg->CR50 = 0x10;
1150        else
1151                reg->CR50 = 0x30;
1152
1153        if (var->xres_virtual <= 640)
1154                reg->CR50 |= 0x40;
1155        else if (var->xres_virtual == 800)
1156                reg->CR50 |= 0x80;
1157        else if (var->xres_virtual == 1024)
1158                reg->CR50 |= 0x00;
1159        else if (var->xres_virtual == 1152)
1160                reg->CR50 |= 0x01;
1161        else if (var->xres_virtual == 1280)
1162                reg->CR50 |= 0xc0;
1163        else if (var->xres_virtual == 1600)
1164                reg->CR50 |= 0x81;
1165        else
1166                reg->CR50 |= 0xc1;      /* Use GBD */
1167
1168        if (par->chip == S3_SAVAGE2000)
1169                reg->CR33 = 0x08;
1170        else
1171                reg->CR33 = 0x20;
1172
1173        reg->CRTC[0x17] = 0xeb;
1174
1175        reg->CR67 |= 1;
1176
1177        vga_out8(0x3d4, 0x36, par);
1178        reg->CR36 = vga_in8(0x3d5, par);
1179        vga_out8(0x3d4, 0x68, par);
1180        reg->CR68 = vga_in8(0x3d5, par);
1181        reg->CR69 = 0;
1182        vga_out8(0x3d4, 0x6f, par);
1183        reg->CR6F = vga_in8(0x3d5, par);
1184        vga_out8(0x3d4, 0x86, par);
1185        reg->CR86 = vga_in8(0x3d5, par);
1186        vga_out8(0x3d4, 0x88, par);
1187        reg->CR88 = vga_in8(0x3d5, par) | 0x08;
1188        vga_out8(0x3d4, 0xb0, par);
1189        reg->CRB0 = vga_in8(0x3d5, par) | 0x80;
1190
1191        return 0;
1192}
1193
1194/* --------------------------------------------------------------------- */
1195
1196/*
1197 *    Set a single color register. Return != 0 for invalid regno.
1198 */
1199static int savagefb_setcolreg(unsigned        regno,
1200                              unsigned        red,
1201                              unsigned        green,
1202                              unsigned        blue,
1203                              unsigned        transp,
1204                              struct fb_info *info)
1205{
1206        struct savagefb_par *par = info->par;
1207
1208        if (regno >= NR_PALETTE)
1209                return -EINVAL;
1210
1211        par->palette[regno].red    = red;
1212        par->palette[regno].green  = green;
1213        par->palette[regno].blue   = blue;
1214        par->palette[regno].transp = transp;
1215
1216        switch (info->var.bits_per_pixel) {
1217        case 8:
1218                vga_out8(0x3c8, regno, par);
1219
1220                vga_out8(0x3c9, red   >> 10, par);
1221                vga_out8(0x3c9, green >> 10, par);
1222                vga_out8(0x3c9, blue  >> 10, par);
1223                break;
1224
1225        case 16:
1226                if (regno < 16)
1227                        ((u32 *)info->pseudo_palette)[regno] =
1228                                ((red   & 0xf800)      ) |
1229                                ((green & 0xfc00) >>  5) |
1230                                ((blue  & 0xf800) >> 11);
1231                break;
1232
1233        case 24:
1234                if (regno < 16)
1235                        ((u32 *)info->pseudo_palette)[regno] =
1236                                ((red    & 0xff00) <<  8) |
1237                                ((green  & 0xff00)      ) |
1238                                ((blue   & 0xff00) >>  8);
1239                break;
1240        case 32:
1241                if (regno < 16)
1242                        ((u32 *)info->pseudo_palette)[regno] =
1243                                ((transp & 0xff00) << 16) |
1244                                ((red    & 0xff00) <<  8) |
1245                                ((green  & 0xff00)      ) |
1246                                ((blue   & 0xff00) >>  8);
1247                break;
1248
1249        default:
1250                return 1;
1251        }
1252
1253        return 0;
1254}
1255
1256static void savagefb_set_par_int(struct savagefb_par  *par, struct savage_reg *reg)
1257{
1258        unsigned char tmp, cr3a, cr66, cr67;
1259
1260        DBG("savagefb_set_par_int");
1261
1262        par->SavageWaitIdle(par);
1263
1264        vga_out8(0x3c2, 0x23, par);
1265
1266        vga_out16(0x3d4, 0x4838, par);
1267        vga_out16(0x3d4, 0xa539, par);
1268        vga_out16(0x3c4, 0x0608, par);
1269
1270        vgaHWProtect(par, 1);
1271
1272        /*
1273         * Some Savage/MX and /IX systems go nuts when trying to exit the
1274         * server after WindowMaker has displayed a gradient background.  I
1275         * haven't been able to find what causes it, but a non-destructive
1276         * switch to mode 3 here seems to eliminate the issue.
1277         */
1278
1279        VerticalRetraceWait(par);
1280        vga_out8(0x3d4, 0x67, par);
1281        cr67 = vga_in8(0x3d5, par);
1282        vga_out8(0x3d5, cr67/*par->CR67*/ & ~0x0c, par); /* no STREAMS yet */
1283
1284        vga_out8(0x3d4, 0x23, par);
1285        vga_out8(0x3d5, 0x00, par);
1286        vga_out8(0x3d4, 0x26, par);
1287        vga_out8(0x3d5, 0x00, par);
1288
1289        /* restore extended regs */
1290        vga_out8(0x3d4, 0x66, par);
1291        vga_out8(0x3d5, reg->CR66, par);
1292        vga_out8(0x3d4, 0x3a, par);
1293        vga_out8(0x3d5, reg->CR3A, par);
1294        vga_out8(0x3d4, 0x31, par);
1295        vga_out8(0x3d5, reg->CR31, par);
1296        vga_out8(0x3d4, 0x32, par);
1297        vga_out8(0x3d5, reg->CR32, par);
1298        vga_out8(0x3d4, 0x58, par);
1299        vga_out8(0x3d5, reg->CR58, par);
1300        vga_out8(0x3d4, 0x53, par);
1301        vga_out8(0x3d5, reg->CR53 & 0x7f, par);
1302
1303        vga_out16(0x3c4, 0x0608, par);
1304
1305        /* Restore DCLK registers. */
1306
1307        vga_out8(0x3c4, 0x0e, par);
1308        vga_out8(0x3c5, reg->SR0E, par);
1309        vga_out8(0x3c4, 0x0f, par);
1310        vga_out8(0x3c5, reg->SR0F, par);
1311        vga_out8(0x3c4, 0x29, par);
1312        vga_out8(0x3c5, reg->SR29, par);
1313        vga_out8(0x3c4, 0x15, par);
1314        vga_out8(0x3c5, reg->SR15, par);
1315
1316        /* Restore flat panel expansion registers. */
1317        if (par->chip == S3_SAVAGE_MX) {
1318                int i;
1319
1320                for (i = 0; i < 8; i++) {
1321                        vga_out8(0x3c4, 0x54+i, par);
1322                        vga_out8(0x3c5, reg->SR54[i], par);
1323                }
1324        }
1325
1326        vgaHWRestore (par, reg);
1327
1328        /* extended mode timing registers */
1329        vga_out8(0x3d4, 0x53, par);
1330        vga_out8(0x3d5, reg->CR53, par);
1331        vga_out8(0x3d4, 0x5d, par);
1332        vga_out8(0x3d5, reg->CR5D, par);
1333        vga_out8(0x3d4, 0x5e, par);
1334        vga_out8(0x3d5, reg->CR5E, par);
1335        vga_out8(0x3d4, 0x3b, par);
1336        vga_out8(0x3d5, reg->CR3B, par);
1337        vga_out8(0x3d4, 0x3c, par);
1338        vga_out8(0x3d5, reg->CR3C, par);
1339        vga_out8(0x3d4, 0x43, par);
1340        vga_out8(0x3d5, reg->CR43, par);
1341        vga_out8(0x3d4, 0x65, par);
1342        vga_out8(0x3d5, reg->CR65, par);
1343
1344        /* restore the desired video mode with cr67 */
1345        vga_out8(0x3d4, 0x67, par);
1346        /* following part not present in X11 driver */
1347        cr67 = vga_in8(0x3d5, par) & 0xf;
1348        vga_out8(0x3d5, 0x50 | cr67, par);
1349        mdelay(10);
1350        vga_out8(0x3d4, 0x67, par);
1351        /* end of part */
1352        vga_out8(0x3d5, reg->CR67 & ~0x0c, par);
1353
1354        /* other mode timing and extended regs */
1355        vga_out8(0x3d4, 0x34, par);
1356        vga_out8(0x3d5, reg->CR34, par);
1357        vga_out8(0x3d4, 0x40, par);
1358        vga_out8(0x3d5, reg->CR40, par);
1359        vga_out8(0x3d4, 0x42, par);
1360        vga_out8(0x3d5, reg->CR42, par);
1361        vga_out8(0x3d4, 0x45, par);
1362        vga_out8(0x3d5, reg->CR45, par);
1363        vga_out8(0x3d4, 0x50, par);
1364        vga_out8(0x3d5, reg->CR50, par);
1365        vga_out8(0x3d4, 0x51, par);
1366        vga_out8(0x3d5, reg->CR51, par);
1367
1368        /* memory timings */
1369        vga_out8(0x3d4, 0x36, par);
1370        vga_out8(0x3d5, reg->CR36, par);
1371        vga_out8(0x3d4, 0x60, par);
1372        vga_out8(0x3d5, reg->CR60, par);
1373        vga_out8(0x3d4, 0x68, par);
1374        vga_out8(0x3d5, reg->CR68, par);
1375        vga_out8(0x3d4, 0x69, par);
1376        vga_out8(0x3d5, reg->CR69, par);
1377        vga_out8(0x3d4, 0x6f, par);
1378        vga_out8(0x3d5, reg->CR6F, par);
1379
1380        vga_out8(0x3d4, 0x33, par);
1381        vga_out8(0x3d5, reg->CR33, par);
1382        vga_out8(0x3d4, 0x86, par);
1383        vga_out8(0x3d5, reg->CR86, par);
1384        vga_out8(0x3d4, 0x88, par);
1385        vga_out8(0x3d5, reg->CR88, par);
1386        vga_out8(0x3d4, 0x90, par);
1387        vga_out8(0x3d5, reg->CR90, par);
1388        vga_out8(0x3d4, 0x91, par);
1389        vga_out8(0x3d5, reg->CR91, par);
1390
1391        if (par->chip == S3_SAVAGE4) {
1392                vga_out8(0x3d4, 0xb0, par);
1393                vga_out8(0x3d5, reg->CRB0, par);
1394        }
1395
1396        vga_out8(0x3d4, 0x32, par);
1397        vga_out8(0x3d5, reg->CR32, par);
1398
1399        /* unlock extended seq regs */
1400        vga_out8(0x3c4, 0x08, par);
1401        vga_out8(0x3c5, 0x06, par);
1402
1403        /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates
1404         * that we should leave the default SR10 and SR11 values there.
1405         */
1406        if (reg->SR10 != 255) {
1407                vga_out8(0x3c4, 0x10, par);
1408                vga_out8(0x3c5, reg->SR10, par);
1409                vga_out8(0x3c4, 0x11, par);
1410                vga_out8(0x3c5, reg->SR11, par);
1411        }
1412
1413        /* restore extended seq regs for dclk */
1414        vga_out8(0x3c4, 0x0e, par);
1415        vga_out8(0x3c5, reg->SR0E, par);
1416        vga_out8(0x3c4, 0x0f, par);
1417        vga_out8(0x3c5, reg->SR0F, par);
1418        vga_out8(0x3c4, 0x12, par);
1419        vga_out8(0x3c5, reg->SR12, par);
1420        vga_out8(0x3c4, 0x13, par);
1421        vga_out8(0x3c5, reg->SR13, par);
1422        vga_out8(0x3c4, 0x29, par);
1423        vga_out8(0x3c5, reg->SR29, par);
1424        vga_out8(0x3c4, 0x18, par);
1425        vga_out8(0x3c5, reg->SR18, par);
1426
1427        /* load new m, n pll values for dclk & mclk */
1428        vga_out8(0x3c4, 0x15, par);
1429        tmp = vga_in8(0x3c5, par) & ~0x21;
1430
1431        vga_out8(0x3c5, tmp | 0x03, par);
1432        vga_out8(0x3c5, tmp | 0x23, par);
1433        vga_out8(0x3c5, tmp | 0x03, par);
1434        vga_out8(0x3c5, reg->SR15, par);
1435        udelay(100);
1436
1437        vga_out8(0x3c4, 0x30, par);
1438        vga_out8(0x3c5, reg->SR30, par);
1439        vga_out8(0x3c4, 0x08, par);
1440        vga_out8(0x3c5, reg->SR08, par);
1441
1442        /* now write out cr67 in full, possibly starting STREAMS */
1443        VerticalRetraceWait(par);
1444        vga_out8(0x3d4, 0x67, par);
1445        vga_out8(0x3d5, reg->CR67, par);
1446
1447        vga_out8(0x3d4, 0x66, par);
1448        cr66 = vga_in8(0x3d5, par);
1449        vga_out8(0x3d5, cr66 | 0x80, par);
1450        vga_out8(0x3d4, 0x3a, par);
1451        cr3a = vga_in8(0x3d5, par);
1452        vga_out8(0x3d5, cr3a | 0x80, par);
1453
1454        if (par->chip != S3_SAVAGE_MX) {
1455                VerticalRetraceWait(par);
1456                savage_out32(FIFO_CONTROL_REG, reg->MMPR0, par);
1457                par->SavageWaitIdle(par);
1458                savage_out32(MIU_CONTROL_REG, reg->MMPR1, par);
1459                par->SavageWaitIdle(par);
1460                savage_out32(STREAMS_TIMEOUT_REG, reg->MMPR2, par);
1461                par->SavageWaitIdle(par);
1462                savage_out32(MISC_TIMEOUT_REG, reg->MMPR3, par);
1463        }
1464
1465        vga_out8(0x3d4, 0x66, par);
1466        vga_out8(0x3d5, cr66, par);
1467        vga_out8(0x3d4, 0x3a, par);
1468        vga_out8(0x3d5, cr3a, par);
1469
1470        SavageSetup2DEngine(par);
1471        vgaHWProtect(par, 0);
1472}
1473
1474static void savagefb_update_start(struct savagefb_par *par, int base)
1475{
1476        /* program the start address registers */
1477        vga_out16(0x3d4, (base & 0x00ff00) | 0x0c, par);
1478        vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d, par);
1479        vga_out8(0x3d4, 0x69, par);
1480        vga_out8(0x3d5, (base & 0x7f0000) >> 16, par);
1481}
1482
1483
1484static void savagefb_set_fix(struct fb_info *info)
1485{
1486        info->fix.line_length = info->var.xres_virtual *
1487                info->var.bits_per_pixel / 8;
1488
1489        if (info->var.bits_per_pixel == 8) {
1490                info->fix.visual      = FB_VISUAL_PSEUDOCOLOR;
1491                info->fix.xpanstep    = 4;
1492        } else {
1493                info->fix.visual      = FB_VISUAL_TRUECOLOR;
1494                info->fix.xpanstep    = 2;
1495        }
1496
1497}
1498
1499static int savagefb_set_par(struct fb_info *info)
1500{
1501        struct savagefb_par *par = info->par;
1502        struct fb_var_screeninfo *var = &info->var;
1503        int err;
1504
1505        DBG("savagefb_set_par");
1506        err = savagefb_decode_var(var, par, &par->state);
1507        if (err)
1508                return err;
1509
1510        if (par->dacSpeedBpp <= 0) {
1511                if (var->bits_per_pixel > 24)
1512                        par->dacSpeedBpp = par->clock[3];
1513                else if (var->bits_per_pixel >= 24)
1514                        par->dacSpeedBpp = par->clock[2];
1515                else if ((var->bits_per_pixel > 8) && (var->bits_per_pixel < 24))
1516                        par->dacSpeedBpp = par->clock[1];
1517                else if (var->bits_per_pixel <= 8)
1518                        par->dacSpeedBpp = par->clock[0];
1519        }
1520
1521        /* Set ramdac limits */
1522        par->maxClock = par->dacSpeedBpp;
1523        par->minClock = 10000;
1524
1525        savagefb_set_par_int(par, &par->state);
1526        fb_set_cmap(&info->cmap, info);
1527        savagefb_set_fix(info);
1528        savagefb_set_clip(info);
1529
1530        SavagePrintRegs(par);
1531        return 0;
1532}
1533
1534/*
1535 *    Pan or Wrap the Display
1536 */
1537static int savagefb_pan_display(struct fb_var_screeninfo *var,
1538                                struct fb_info           *info)
1539{
1540        struct savagefb_par *par = info->par;
1541        int base;
1542
1543        base = (var->yoffset * info->fix.line_length
1544             + (var->xoffset & ~1) * ((info->var.bits_per_pixel+7) / 8)) >> 2;
1545
1546        savagefb_update_start(par, base);
1547        return 0;
1548}
1549
1550static int savagefb_blank(int blank, struct fb_info *info)
1551{
1552        struct savagefb_par *par = info->par;
1553        u8 sr8 = 0, srd = 0;
1554
1555        if (par->display_type == DISP_CRT) {
1556                vga_out8(0x3c4, 0x08, par);
1557                sr8 = vga_in8(0x3c5, par);
1558                sr8 |= 0x06;
1559                vga_out8(0x3c5, sr8, par);
1560                vga_out8(0x3c4, 0x0d, par);
1561                srd = vga_in8(0x3c5, par);
1562                srd &= 0x50;
1563
1564                switch (blank) {
1565                case FB_BLANK_UNBLANK:
1566                case FB_BLANK_NORMAL:
1567                        break;
1568                case FB_BLANK_VSYNC_SUSPEND:
1569                        srd |= 0x10;
1570                        break;
1571                case FB_BLANK_HSYNC_SUSPEND:
1572                        srd |= 0x40;
1573                        break;
1574                case FB_BLANK_POWERDOWN:
1575                        srd |= 0x50;
1576                        break;
1577                }
1578
1579                vga_out8(0x3c4, 0x0d, par);
1580                vga_out8(0x3c5, srd, par);
1581        }
1582
1583        if (par->display_type == DISP_LCD ||
1584            par->display_type == DISP_DFP) {
1585                switch(blank) {
1586                case FB_BLANK_UNBLANK:
1587                case FB_BLANK_NORMAL:
1588                        vga_out8(0x3c4, 0x31, par); /* SR31 bit 4 - FP enable */
1589                        vga_out8(0x3c5, vga_in8(0x3c5, par) | 0x10, par);
1590                        break;
1591                case FB_BLANK_VSYNC_SUSPEND:
1592                case FB_BLANK_HSYNC_SUSPEND:
1593                case FB_BLANK_POWERDOWN:
1594                        vga_out8(0x3c4, 0x31, par); /* SR31 bit 4 - FP enable */
1595                        vga_out8(0x3c5, vga_in8(0x3c5, par) & ~0x10, par);
1596                        break;
1597                }
1598        }
1599
1600        return (blank == FB_BLANK_NORMAL) ? 1 : 0;
1601}
1602
1603static int savagefb_open(struct fb_info *info, int user)
1604{
1605        struct savagefb_par *par = info->par;
1606
1607        mutex_lock(&par->open_lock);
1608
1609        if (!par->open_count) {
1610                memset(&par->vgastate, 0, sizeof(par->vgastate));
1611                par->vgastate.flags = VGA_SAVE_CMAP | VGA_SAVE_FONTS |
1612                        VGA_SAVE_MODE;
1613                par->vgastate.vgabase = par->mmio.vbase + 0x8000;
1614                save_vga(&par->vgastate);
1615                savage_get_default_par(par, &par->initial);
1616        }
1617
1618        par->open_count++;
1619        mutex_unlock(&par->open_lock);
1620        return 0;
1621}
1622
1623static int savagefb_release(struct fb_info *info, int user)
1624{
1625        struct savagefb_par *par = info->par;
1626
1627        mutex_lock(&par->open_lock);
1628
1629        if (par->open_count == 1) {
1630                savage_set_default_par(par, &par->initial);
1631                restore_vga(&par->vgastate);
1632        }
1633
1634        par->open_count--;
1635        mutex_unlock(&par->open_lock);
1636        return 0;
1637}
1638
1639static const struct fb_ops savagefb_ops = {
1640        .owner          = THIS_MODULE,
1641        .fb_open        = savagefb_open,
1642        .fb_release     = savagefb_release,
1643        .fb_check_var   = savagefb_check_var,
1644        .fb_set_par     = savagefb_set_par,
1645        .fb_setcolreg   = savagefb_setcolreg,
1646        .fb_pan_display = savagefb_pan_display,
1647        .fb_blank       = savagefb_blank,
1648#if defined(CONFIG_FB_SAVAGE_ACCEL)
1649        .fb_fillrect    = savagefb_fillrect,
1650        .fb_copyarea    = savagefb_copyarea,
1651        .fb_imageblit   = savagefb_imageblit,
1652        .fb_sync        = savagefb_sync,
1653#else
1654        .fb_fillrect    = cfb_fillrect,
1655        .fb_copyarea    = cfb_copyarea,
1656        .fb_imageblit   = cfb_imageblit,
1657#endif
1658};
1659
1660/* --------------------------------------------------------------------- */
1661
1662static const struct fb_var_screeninfo savagefb_var800x600x8 = {
1663        .accel_flags =  FB_ACCELF_TEXT,
1664        .xres =         800,
1665        .yres =         600,
1666        .xres_virtual =  800,
1667        .yres_virtual =  600,
1668        .bits_per_pixel = 8,
1669        .pixclock =     25000,
1670        .left_margin =  88,
1671        .right_margin = 40,
1672        .upper_margin = 23,
1673        .lower_margin = 1,
1674        .hsync_len =    128,
1675        .vsync_len =    4,
1676        .sync =         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
1677        .vmode =        FB_VMODE_NONINTERLACED
1678};
1679
1680static void savage_enable_mmio(struct savagefb_par *par)
1681{
1682        unsigned char val;
1683
1684        DBG("savage_enable_mmio\n");
1685
1686        val = vga_in8(0x3c3, par);
1687        vga_out8(0x3c3, val | 0x01, par);
1688        val = vga_in8(0x3cc, par);
1689        vga_out8(0x3c2, val | 0x01, par);
1690
1691        if (par->chip >= S3_SAVAGE4) {
1692                vga_out8(0x3d4, 0x40, par);
1693                val = vga_in8(0x3d5, par);
1694                vga_out8(0x3d5, val | 1, par);
1695        }
1696}
1697
1698
1699static void savage_disable_mmio(struct savagefb_par *par)
1700{
1701        unsigned char val;
1702
1703        DBG("savage_disable_mmio\n");
1704
1705        if (par->chip >= S3_SAVAGE4) {
1706                vga_out8(0x3d4, 0x40, par);
1707                val = vga_in8(0x3d5, par);
1708                vga_out8(0x3d5, val | 1, par);
1709        }
1710}
1711
1712
1713static int savage_map_mmio(struct fb_info *info)
1714{
1715        struct savagefb_par *par = info->par;
1716        DBG("savage_map_mmio");
1717
1718        if (S3_SAVAGE3D_SERIES(par->chip))
1719                par->mmio.pbase = pci_resource_start(par->pcidev, 0) +
1720                        SAVAGE_NEWMMIO_REGBASE_S3;
1721        else
1722                par->mmio.pbase = pci_resource_start(par->pcidev, 0) +
1723                        SAVAGE_NEWMMIO_REGBASE_S4;
1724
1725        par->mmio.len = SAVAGE_NEWMMIO_REGSIZE;
1726
1727        par->mmio.vbase = ioremap(par->mmio.pbase, par->mmio.len);
1728        if (!par->mmio.vbase) {
1729                printk("savagefb: unable to map memory mapped IO\n");
1730                return -ENOMEM;
1731        } else
1732                printk(KERN_INFO "savagefb: mapped io at %p\n",
1733                        par->mmio.vbase);
1734
1735        info->fix.mmio_start = par->mmio.pbase;
1736        info->fix.mmio_len   = par->mmio.len;
1737
1738        par->bci_base = (u32 __iomem *)(par->mmio.vbase + BCI_BUFFER_OFFSET);
1739        par->bci_ptr  = 0;
1740
1741        savage_enable_mmio(par);
1742
1743        return 0;
1744}
1745
1746static void savage_unmap_mmio(struct fb_info *info)
1747{
1748        struct savagefb_par *par = info->par;
1749        DBG("savage_unmap_mmio");
1750
1751        savage_disable_mmio(par);
1752
1753        if (par->mmio.vbase) {
1754                iounmap(par->mmio.vbase);
1755                par->mmio.vbase = NULL;
1756        }
1757}
1758
1759static int savage_map_video(struct fb_info *info, int video_len)
1760{
1761        struct savagefb_par *par = info->par;
1762        int resource;
1763
1764        DBG("savage_map_video");
1765
1766        if (S3_SAVAGE3D_SERIES(par->chip))
1767                resource = 0;
1768        else
1769                resource = 1;
1770
1771        par->video.pbase = pci_resource_start(par->pcidev, resource);
1772        par->video.len   = video_len;
1773        par->video.vbase = ioremap_wc(par->video.pbase, par->video.len);
1774
1775        if (!par->video.vbase) {
1776                printk("savagefb: unable to map screen memory\n");
1777                return -ENOMEM;
1778        } else
1779                printk(KERN_INFO "savagefb: mapped framebuffer at %p, "
1780                       "pbase == %x\n", par->video.vbase, par->video.pbase);
1781
1782        info->fix.smem_start = par->video.pbase;
1783        info->fix.smem_len   = par->video.len - par->cob_size;
1784        info->screen_base    = par->video.vbase;
1785        par->video.wc_cookie = arch_phys_wc_add(par->video.pbase, video_len);
1786
1787        /* Clear framebuffer, it's all white in memory after boot */
1788        memset_io(par->video.vbase, 0, par->video.len);
1789
1790        return 0;
1791}
1792
1793static void savage_unmap_video(struct fb_info *info)
1794{
1795        struct savagefb_par *par = info->par;
1796
1797        DBG("savage_unmap_video");
1798
1799        if (par->video.vbase) {
1800                arch_phys_wc_del(par->video.wc_cookie);
1801                iounmap(par->video.vbase);
1802                par->video.vbase = NULL;
1803                info->screen_base = NULL;
1804        }
1805}
1806
1807static int savage_init_hw(struct savagefb_par *par)
1808{
1809        unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp;
1810
1811        static unsigned char RamSavage3D[] = { 8, 4, 4, 2 };
1812        static unsigned char RamSavage4[] =  { 2, 4, 8, 12, 16, 32, 64, 32 };
1813        static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
1814        static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 2, 2 };
1815        int videoRam, videoRambytes, dvi;
1816
1817        DBG("savage_init_hw");
1818
1819        /* unprotect CRTC[0-7] */
1820        vga_out8(0x3d4, 0x11, par);
1821        tmp = vga_in8(0x3d5, par);
1822        vga_out8(0x3d5, tmp & 0x7f, par);
1823
1824        /* unlock extended regs */
1825        vga_out16(0x3d4, 0x4838, par);
1826        vga_out16(0x3d4, 0xa039, par);
1827        vga_out16(0x3c4, 0x0608, par);
1828
1829        vga_out8(0x3d4, 0x40, par);
1830        tmp = vga_in8(0x3d5, par);
1831        vga_out8(0x3d5, tmp & ~0x01, par);
1832
1833        /* unlock sys regs */
1834        vga_out8(0x3d4, 0x38, par);
1835        vga_out8(0x3d5, 0x48, par);
1836
1837        /* Unlock system registers. */
1838        vga_out16(0x3d4, 0x4838, par);
1839
1840        /* Next go on to detect amount of installed ram */
1841
1842        vga_out8(0x3d4, 0x36, par);            /* for register CR36 (CONFG_REG1), */
1843        config1 = vga_in8(0x3d5, par);    /* get amount of vram installed */
1844
1845        /* Compute the amount of video memory and offscreen memory. */
1846
1847        switch  (par->chip) {
1848        case S3_SAVAGE3D:
1849                videoRam = RamSavage3D[(config1 & 0xC0) >> 6 ] * 1024;
1850                break;
1851
1852        case S3_SAVAGE4:
1853                /*
1854                 * The Savage4 has one ugly special case to consider.  On
1855                 * systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB
1856                 * when it really means 8MB.  Why do it the same when you
1857                 * can do it different...
1858                 */
1859                vga_out8(0x3d4, 0x68, par);     /* memory control 1 */
1860                if ((vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6))
1861                        RamSavage4[1] = 8;
1862                fallthrough;
1863
1864        case S3_SAVAGE2000:
1865                videoRam = RamSavage4[(config1 & 0xE0) >> 5] * 1024;
1866                break;
1867
1868        case S3_SAVAGE_MX:
1869        case S3_SUPERSAVAGE:
1870                videoRam = RamSavageMX[(config1 & 0x0E) >> 1] * 1024;
1871                break;
1872
1873        case S3_PROSAVAGE:
1874        case S3_PROSAVAGEDDR:
1875        case S3_TWISTER:
1876                videoRam = RamSavageNB[(config1 & 0xE0) >> 5] * 1024;
1877                break;
1878
1879        default:
1880                /* How did we get here? */
1881                videoRam = 0;
1882                break;
1883        }
1884
1885        videoRambytes = videoRam * 1024;
1886
1887        printk(KERN_INFO "savagefb: probed videoram:  %dk\n", videoRam);
1888
1889        /* reset graphics engine to avoid memory corruption */
1890        vga_out8(0x3d4, 0x66, par);
1891        cr66 = vga_in8(0x3d5, par);
1892        vga_out8(0x3d5, cr66 | 0x02, par);
1893        usleep_range(10000, 11000);
1894
1895        vga_out8(0x3d4, 0x66, par);
1896        vga_out8(0x3d5, cr66 & ~0x02, par);     /* clear reset flag */
1897        usleep_range(10000, 11000);
1898
1899
1900        /*
1901         * reset memory interface, 3D engine, AGP master, PCI master,
1902         * master engine unit, motion compensation/LPB
1903         */
1904        vga_out8(0x3d4, 0x3f, par);
1905        cr3f = vga_in8(0x3d5, par);
1906        vga_out8(0x3d5, cr3f | 0x08, par);
1907        usleep_range(10000, 11000);
1908
1909        vga_out8(0x3d4, 0x3f, par);
1910        vga_out8(0x3d5, cr3f & ~0x08, par);     /* clear reset flags */
1911        usleep_range(10000, 11000);
1912
1913        /* Savage ramdac speeds */
1914        par->numClocks = 4;
1915        par->clock[0] = 250000;
1916        par->clock[1] = 250000;
1917        par->clock[2] = 220000;
1918        par->clock[3] = 220000;
1919
1920        /* detect current mclk */
1921        vga_out8(0x3c4, 0x08, par);
1922        sr8 = vga_in8(0x3c5, par);
1923        vga_out8(0x3c5, 0x06, par);
1924        vga_out8(0x3c4, 0x10, par);
1925        n = vga_in8(0x3c5, par);
1926        vga_out8(0x3c4, 0x11, par);
1927        m = vga_in8(0x3c5, par);
1928        vga_out8(0x3c4, 0x08, par);
1929        vga_out8(0x3c5, sr8, par);
1930        m &= 0x7f;
1931        n1 = n & 0x1f;
1932        n2 = (n >> 5) & 0x03;
1933        par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
1934        printk(KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n",
1935                par->MCLK);
1936
1937        /* check for DVI/flat panel */
1938        dvi = 0;
1939
1940        if (par->chip == S3_SAVAGE4) {
1941                unsigned char sr30 = 0x00;
1942
1943                vga_out8(0x3c4, 0x30, par);
1944                /* clear bit 1 */
1945                vga_out8(0x3c5, vga_in8(0x3c5, par) & ~0x02, par);
1946                sr30 = vga_in8(0x3c5, par);
1947                if (sr30 & 0x02 /*0x04 */) {
1948                        dvi = 1;
1949                        printk("savagefb: Digital Flat Panel Detected\n");
1950                }
1951        }
1952
1953        if ((S3_SAVAGE_MOBILE_SERIES(par->chip) ||
1954             S3_MOBILE_TWISTER_SERIES(par->chip)) && !par->crtonly)
1955                par->display_type = DISP_LCD;
1956        else if (dvi || (par->chip == S3_SAVAGE4 && par->dvi))
1957                par->display_type = DISP_DFP;
1958        else
1959                par->display_type = DISP_CRT;
1960
1961        /* Check LCD panel parrmation */
1962
1963        if (par->display_type == DISP_LCD) {
1964                unsigned char cr6b = VGArCR(0x6b, par);
1965
1966                int panelX = (VGArSEQ(0x61, par) +
1967                              ((VGArSEQ(0x66, par) & 0x02) << 7) + 1) * 8;
1968                int panelY = (VGArSEQ(0x69, par) +
1969                              ((VGArSEQ(0x6e, par) & 0x70) << 4) + 1);
1970
1971                char * sTechnology = "Unknown";
1972
1973                /* OK, I admit it.  I don't know how to limit the max dot clock
1974                 * for LCD panels of various sizes.  I thought I copied the
1975                 * formula from the BIOS, but many users have parrmed me of
1976                 * my folly.
1977                 *
1978                 * Instead, I'll abandon any attempt to automatically limit the
1979                 * clock, and add an LCDClock option to XF86Config.  Some day,
1980                 * I should come back to this.
1981                 */
1982
1983                enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */
1984                        ActiveCRT = 0x01,
1985                        ActiveLCD = 0x02,
1986                        ActiveTV = 0x04,
1987                        ActiveCRT2 = 0x20,
1988                        ActiveDUO = 0x80
1989                };
1990
1991                if ((VGArSEQ(0x39, par) & 0x03) == 0) {
1992                        sTechnology = "TFT";
1993                } else if ((VGArSEQ(0x30, par) & 0x01) == 0) {
1994                        sTechnology = "DSTN";
1995                } else  {
1996                        sTechnology = "STN";
1997                }
1998
1999                printk(KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n",
2000                       panelX, panelY, sTechnology,
2001                       cr6b & ActiveLCD ? "and active" : "but not active");
2002
2003                if (cr6b & ActiveLCD)   {
2004                        /*
2005                         * If the LCD is active and panel expansion is enabled,
2006                         * we probably want to kill the HW cursor.
2007                         */
2008
2009                        printk(KERN_INFO "savagefb: Limiting video mode to "
2010                                "%dx%d\n", panelX, panelY);
2011
2012                        par->SavagePanelWidth = panelX;
2013                        par->SavagePanelHeight = panelY;
2014
2015                } else
2016                        par->display_type = DISP_CRT;
2017        }
2018
2019        savage_get_default_par(par, &par->state);
2020        par->save = par->state;
2021
2022        if (S3_SAVAGE4_SERIES(par->chip)) {
2023                /*
2024                 * The Savage4 and ProSavage have COB coherency bugs which
2025                 * render the buffer useless.  We disable it.
2026                 */
2027                par->cob_index = 2;
2028                par->cob_size = 0x8000 << par->cob_index;
2029                par->cob_offset = videoRambytes;
2030        } else {
2031                /* We use 128kB for the COB on all chips. */
2032
2033                par->cob_index  = 7;
2034                par->cob_size   = 0x400 << par->cob_index;
2035                par->cob_offset = videoRambytes - par->cob_size;
2036        }
2037
2038        return videoRambytes;
2039}
2040
2041static int savage_init_fb_info(struct fb_info *info, struct pci_dev *dev,
2042                               const struct pci_device_id *id)
2043{
2044        struct savagefb_par *par = info->par;
2045        int err = 0;
2046
2047        par->pcidev  = dev;
2048
2049        info->fix.type     = FB_TYPE_PACKED_PIXELS;
2050        info->fix.type_aux         = 0;
2051        info->fix.ypanstep         = 1;
2052        info->fix.ywrapstep   = 0;
2053        info->fix.accel       = id->driver_data;
2054
2055        switch (info->fix.accel) {
2056        case FB_ACCEL_SUPERSAVAGE:
2057                par->chip = S3_SUPERSAVAGE;
2058                snprintf(info->fix.id, 16, "SuperSavage");
2059                break;
2060        case FB_ACCEL_SAVAGE4:
2061                par->chip = S3_SAVAGE4;
2062                snprintf(info->fix.id, 16, "Savage4");
2063                break;
2064        case FB_ACCEL_SAVAGE3D:
2065                par->chip = S3_SAVAGE3D;
2066                snprintf(info->fix.id, 16, "Savage3D");
2067                break;
2068        case FB_ACCEL_SAVAGE3D_MV:
2069                par->chip = S3_SAVAGE3D;
2070                snprintf(info->fix.id, 16, "Savage3D-MV");
2071                break;
2072        case FB_ACCEL_SAVAGE2000:
2073                par->chip = S3_SAVAGE2000;
2074                snprintf(info->fix.id, 16, "Savage2000");
2075                break;
2076        case FB_ACCEL_SAVAGE_MX_MV:
2077                par->chip = S3_SAVAGE_MX;
2078                snprintf(info->fix.id, 16, "Savage/MX-MV");
2079                break;
2080        case FB_ACCEL_SAVAGE_MX:
2081                par->chip = S3_SAVAGE_MX;
2082                snprintf(info->fix.id, 16, "Savage/MX");
2083                break;
2084        case FB_ACCEL_SAVAGE_IX_MV:
2085                par->chip = S3_SAVAGE_MX;
2086                snprintf(info->fix.id, 16, "Savage/IX-MV");
2087                break;
2088        case FB_ACCEL_SAVAGE_IX:
2089                par->chip = S3_SAVAGE_MX;
2090                snprintf(info->fix.id, 16, "Savage/IX");
2091                break;
2092        case FB_ACCEL_PROSAVAGE_PM:
2093                par->chip = S3_PROSAVAGE;
2094                snprintf(info->fix.id, 16, "ProSavagePM");
2095                break;
2096        case FB_ACCEL_PROSAVAGE_KM:
2097                par->chip = S3_PROSAVAGE;
2098                snprintf(info->fix.id, 16, "ProSavageKM");
2099                break;
2100        case FB_ACCEL_S3TWISTER_P:
2101                par->chip = S3_TWISTER;
2102                snprintf(info->fix.id, 16, "TwisterP");
2103                break;
2104        case FB_ACCEL_S3TWISTER_K:
2105                par->chip = S3_TWISTER;
2106                snprintf(info->fix.id, 16, "TwisterK");
2107                break;
2108        case FB_ACCEL_PROSAVAGE_DDR:
2109                par->chip = S3_PROSAVAGEDDR;
2110                snprintf(info->fix.id, 16, "ProSavageDDR");
2111                break;
2112        case FB_ACCEL_PROSAVAGE_DDRK:
2113                par->chip = S3_PROSAVAGEDDR;
2114                snprintf(info->fix.id, 16, "ProSavage8");
2115                break;
2116        }
2117
2118        if (S3_SAVAGE3D_SERIES(par->chip)) {
2119                par->SavageWaitIdle = savage3D_waitidle;
2120                par->SavageWaitFifo = savage3D_waitfifo;
2121        } else if (S3_SAVAGE4_SERIES(par->chip) ||
2122                   S3_SUPERSAVAGE == par->chip) {
2123                par->SavageWaitIdle = savage4_waitidle;
2124                par->SavageWaitFifo = savage4_waitfifo;
2125        } else {
2126                par->SavageWaitIdle = savage2000_waitidle;
2127                par->SavageWaitFifo = savage2000_waitfifo;
2128        }
2129
2130        info->var.nonstd      = 0;
2131        info->var.activate    = FB_ACTIVATE_NOW;
2132        info->var.width       = -1;
2133        info->var.height      = -1;
2134        info->var.accel_flags = 0;
2135
2136        info->fbops          = &savagefb_ops;
2137        info->flags          = FBINFO_DEFAULT |
2138                               FBINFO_HWACCEL_YPAN |
2139                               FBINFO_HWACCEL_XPAN;
2140
2141        info->pseudo_palette = par->pseudo_palette;
2142
2143#if defined(CONFIG_FB_SAVAGE_ACCEL)
2144        /* FIFO size + padding for commands */
2145        info->pixmap.addr = kcalloc(8, 1024, GFP_KERNEL);
2146
2147        err = -ENOMEM;
2148        if (info->pixmap.addr) {
2149                info->pixmap.size = 8*1024;
2150                info->pixmap.scan_align = 4;
2151                info->pixmap.buf_align = 4;
2152                info->pixmap.access_align = 32;
2153
2154                err = fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
2155                if (!err)
2156                        info->flags |= FBINFO_HWACCEL_COPYAREA |
2157                                       FBINFO_HWACCEL_FILLRECT |
2158                                       FBINFO_HWACCEL_IMAGEBLIT;
2159                else
2160                        kfree(info->pixmap.addr);
2161        }
2162#endif
2163        return err;
2164}
2165
2166/* --------------------------------------------------------------------- */
2167
2168static int savagefb_probe(struct pci_dev *dev, const struct pci_device_id *id)
2169{
2170        struct fb_info *info;
2171        struct savagefb_par *par;
2172        u_int h_sync, v_sync;
2173        int err, lpitch;
2174        int video_len;
2175
2176        DBG("savagefb_probe");
2177
2178        info = framebuffer_alloc(sizeof(struct savagefb_par), &dev->dev);
2179        if (!info)
2180                return -ENOMEM;
2181        par = info->par;
2182        mutex_init(&par->open_lock);
2183        err = pci_enable_device(dev);
2184        if (err)
2185                goto failed_enable;
2186
2187        if ((err = pci_request_regions(dev, "savagefb"))) {
2188                printk(KERN_ERR "cannot request PCI regions\n");
2189                goto failed_enable;
2190        }
2191
2192        err = -ENOMEM;
2193
2194        if ((err = savage_init_fb_info(info, dev, id)))
2195                goto failed_init;
2196
2197        err = savage_map_mmio(info);
2198        if (err)
2199                goto failed_mmio;
2200
2201        video_len = savage_init_hw(par);
2202        /* FIXME: can't be negative */
2203        if (video_len < 0) {
2204                err = video_len;
2205                goto failed_mmio;
2206        }
2207
2208        err = savage_map_video(info, video_len);
2209        if (err)
2210                goto failed_video;
2211
2212        INIT_LIST_HEAD(&info->modelist);
2213#if defined(CONFIG_FB_SAVAGE_I2C)
2214        savagefb_create_i2c_busses(info);
2215        savagefb_probe_i2c_connector(info, &par->edid);
2216        fb_edid_to_monspecs(par->edid, &info->monspecs);
2217        kfree(par->edid);
2218        fb_videomode_to_modelist(info->monspecs.modedb,
2219                                 info->monspecs.modedb_len,
2220                                 &info->modelist);
2221#endif
2222        info->var = savagefb_var800x600x8;
2223        /* if a panel was detected, default to a CVT mode instead */
2224        if (par->SavagePanelWidth) {
2225                struct fb_videomode cvt_mode;
2226
2227                memset(&cvt_mode, 0, sizeof(cvt_mode));
2228                cvt_mode.xres = par->SavagePanelWidth;
2229                cvt_mode.yres = par->SavagePanelHeight;
2230                cvt_mode.refresh = 60;
2231                /* FIXME: if we know there is only the panel
2232                 * we can enable reduced blanking as well */
2233                if (fb_find_mode_cvt(&cvt_mode, 0, 0))
2234                        printk(KERN_WARNING "No CVT mode found for panel\n");
2235                else if (fb_find_mode(&info->var, info, NULL, NULL, 0,
2236                                      &cvt_mode, 0) != 3)
2237                        info->var = savagefb_var800x600x8;
2238        }
2239
2240        if (mode_option) {
2241                fb_find_mode(&info->var, info, mode_option,
2242                             info->monspecs.modedb, info->monspecs.modedb_len,
2243                             NULL, 8);
2244        } else if (info->monspecs.modedb != NULL) {
2245                const struct fb_videomode *mode;
2246
2247                mode = fb_find_best_display(&info->monspecs, &info->modelist);
2248                savage_update_var(&info->var, mode);
2249        }
2250
2251        /* maximize virtual vertical length */
2252        lpitch = info->var.xres_virtual*((info->var.bits_per_pixel + 7) >> 3);
2253        info->var.yres_virtual = info->fix.smem_len/lpitch;
2254
2255        if (info->var.yres_virtual < info->var.yres) {
2256                err = -ENOMEM;
2257                goto failed;
2258        }
2259
2260#if defined(CONFIG_FB_SAVAGE_ACCEL)
2261        /*
2262         * The clipping coordinates are masked with 0xFFF, so limit our
2263         * virtual resolutions to these sizes.
2264         */
2265        if (info->var.yres_virtual > 0x1000)
2266                info->var.yres_virtual = 0x1000;
2267
2268        if (info->var.xres_virtual > 0x1000)
2269                info->var.xres_virtual = 0x1000;
2270#endif
2271        savagefb_check_var(&info->var, info);
2272        savagefb_set_fix(info);
2273
2274        /*
2275         * Calculate the hsync and vsync frequencies.  Note that
2276         * we split the 1e12 constant up so that we can preserve
2277         * the precision and fit the results into 32-bit registers.
2278         *  (1953125000 * 512 = 1e12)
2279         */
2280        h_sync = 1953125000 / info->var.pixclock;
2281        h_sync = h_sync * 512 / (info->var.xres + info->var.left_margin +
2282                                 info->var.right_margin +
2283                                 info->var.hsync_len);
2284        v_sync = h_sync / (info->var.yres + info->var.upper_margin +
2285                           info->var.lower_margin + info->var.vsync_len);
2286
2287        printk(KERN_INFO "savagefb v" SAVAGEFB_VERSION ": "
2288               "%dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
2289               info->fix.smem_len >> 10,
2290               info->var.xres, info->var.yres,
2291               h_sync / 1000, h_sync % 1000, v_sync);
2292
2293
2294        fb_destroy_modedb(info->monspecs.modedb);
2295        info->monspecs.modedb = NULL;
2296
2297        err = register_framebuffer(info);
2298        if (err < 0)
2299                goto failed;
2300
2301        printk(KERN_INFO "fb: S3 %s frame buffer device\n",
2302               info->fix.id);
2303
2304        /*
2305         * Our driver data
2306         */
2307        pci_set_drvdata(dev, info);
2308
2309        return 0;
2310
2311 failed:
2312#ifdef CONFIG_FB_SAVAGE_I2C
2313        savagefb_delete_i2c_busses(info);
2314#endif
2315        fb_alloc_cmap(&info->cmap, 0, 0);
2316        savage_unmap_video(info);
2317 failed_video:
2318        savage_unmap_mmio(info);
2319 failed_mmio:
2320        kfree(info->pixmap.addr);
2321 failed_init:
2322        pci_release_regions(dev);
2323 failed_enable:
2324        framebuffer_release(info);
2325
2326        return err;
2327}
2328
2329static void savagefb_remove(struct pci_dev *dev)
2330{
2331        struct fb_info *info = pci_get_drvdata(dev);
2332
2333        DBG("savagefb_remove");
2334
2335        if (info) {
2336                unregister_framebuffer(info);
2337
2338#ifdef CONFIG_FB_SAVAGE_I2C
2339                savagefb_delete_i2c_busses(info);
2340#endif
2341                fb_alloc_cmap(&info->cmap, 0, 0);
2342                savage_unmap_video(info);
2343                savage_unmap_mmio(info);
2344                kfree(info->pixmap.addr);
2345                pci_release_regions(dev);
2346                framebuffer_release(info);
2347        }
2348}
2349
2350static int savagefb_suspend_late(struct device *dev, pm_message_t mesg)
2351{
2352        struct fb_info *info = dev_get_drvdata(dev);
2353        struct savagefb_par *par = info->par;
2354
2355        DBG("savagefb_suspend");
2356
2357        if (mesg.event == PM_EVENT_PRETHAW)
2358                mesg.event = PM_EVENT_FREEZE;
2359        par->pm_state = mesg.event;
2360        dev->power.power_state = mesg;
2361
2362        /*
2363         * For PM_EVENT_FREEZE, do not power down so the console
2364         * can remain active.
2365         */
2366        if (mesg.event == PM_EVENT_FREEZE)
2367                return 0;
2368
2369        console_lock();
2370        fb_set_suspend(info, 1);
2371
2372        if (info->fbops->fb_sync)
2373                info->fbops->fb_sync(info);
2374
2375        savagefb_blank(FB_BLANK_POWERDOWN, info);
2376        savage_set_default_par(par, &par->save);
2377        savage_disable_mmio(par);
2378        console_unlock();
2379
2380        return 0;
2381}
2382
2383static int __maybe_unused savagefb_suspend(struct device *dev)
2384{
2385        return savagefb_suspend_late(dev, PMSG_SUSPEND);
2386}
2387
2388static int __maybe_unused savagefb_hibernate(struct device *dev)
2389{
2390        return savagefb_suspend_late(dev, PMSG_HIBERNATE);
2391}
2392
2393static int __maybe_unused savagefb_freeze(struct device *dev)
2394{
2395        return savagefb_suspend_late(dev, PMSG_FREEZE);
2396}
2397
2398static int __maybe_unused savagefb_resume(struct device *dev)
2399{
2400        struct fb_info *info = dev_get_drvdata(dev);
2401        struct savagefb_par *par = info->par;
2402        int cur_state = par->pm_state;
2403
2404        DBG("savage_resume");
2405
2406        par->pm_state = PM_EVENT_ON;
2407
2408        /*
2409         * The adapter was not powered down coming back from a
2410         * PM_EVENT_FREEZE.
2411         */
2412        if (cur_state == PM_EVENT_FREEZE)
2413                return 0;
2414
2415        console_lock();
2416
2417        savage_enable_mmio(par);
2418        savage_init_hw(par);
2419        savagefb_set_par(info);
2420        fb_set_suspend(info, 0);
2421        savagefb_blank(FB_BLANK_UNBLANK, info);
2422        console_unlock();
2423
2424        return 0;
2425}
2426
2427static const struct dev_pm_ops savagefb_pm_ops = {
2428#ifdef CONFIG_PM_SLEEP
2429        .suspend        = savagefb_suspend,
2430        .resume         = savagefb_resume,
2431        .freeze         = savagefb_freeze,
2432        .thaw           = savagefb_resume,
2433        .poweroff       = savagefb_hibernate,
2434        .restore        = savagefb_resume,
2435#endif
2436};
2437
2438static const struct pci_device_id savagefb_devices[] = {
2439        {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX128,
2440         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2441
2442        {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64,
2443         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2444
2445        {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64C,
2446         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2447
2448        {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128SDR,
2449         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2450
2451        {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128DDR,
2452         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2453
2454        {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64SDR,
2455         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2456
2457        {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64DDR,
2458         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2459
2460        {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCSDR,
2461         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2462
2463        {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCDDR,
2464         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2465
2466        {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE4,
2467         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE4},
2468
2469        {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D,
2470         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D},
2471
2472        {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D_MV,
2473         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D_MV},
2474
2475        {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE2000,
2476         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE2000},
2477
2478        {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX_MV,
2479         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX_MV},
2480
2481        {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX,
2482         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX},
2483
2484        {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX_MV,
2485         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX_MV},
2486
2487        {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX,
2488         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX},
2489
2490        {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_PM,
2491         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_PM},
2492
2493        {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_KM,
2494         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_KM},
2495
2496        {PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_P,
2497         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_P},
2498
2499        {PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_K,
2500         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_K},
2501
2502        {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDR,
2503         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDR},
2504
2505        {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDRK,
2506         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDRK},
2507
2508        {0, 0, 0, 0, 0, 0, 0}
2509};
2510
2511MODULE_DEVICE_TABLE(pci, savagefb_devices);
2512
2513static struct pci_driver savagefb_driver = {
2514        .name =     "savagefb",
2515        .id_table = savagefb_devices,
2516        .probe =    savagefb_probe,
2517        .driver.pm = &savagefb_pm_ops,
2518        .remove =   savagefb_remove,
2519};
2520
2521/* **************************** exit-time only **************************** */
2522
2523static void __exit savage_done(void)
2524{
2525        DBG("savage_done");
2526        pci_unregister_driver(&savagefb_driver);
2527}
2528
2529
2530/* ************************* init in-kernel code ************************** */
2531
2532static int __init savagefb_setup(char *options)
2533{
2534#ifndef MODULE
2535        char *this_opt;
2536
2537        if (!options || !*options)
2538                return 0;
2539
2540        while ((this_opt = strsep(&options, ",")) != NULL) {
2541                mode_option = this_opt;
2542        }
2543#endif /* !MODULE */
2544        return 0;
2545}
2546
2547static int __init savagefb_init(void)
2548{
2549        char *option;
2550
2551        DBG("savagefb_init");
2552
2553        if (fb_get_options("savagefb", &option))
2554                return -ENODEV;
2555
2556        savagefb_setup(option);
2557        return pci_register_driver(&savagefb_driver);
2558
2559}
2560
2561module_init(savagefb_init);
2562module_exit(savage_done);
2563
2564module_param(mode_option, charp, 0);
2565MODULE_PARM_DESC(mode_option, "Specify initial video mode");
2566