Subversion Repositories shark

Rev

Blame | Last modification | View Log | RSS feed

/*
Riva 128 driver - Matan Ziv-Av matan@svgalib.org
please report problems to me,

This driver is based on the XFREE86 nv3 driver, developed by
David J. Mckay.

I used the file cirrus.c in this directory as a skeleton.

there are still the following problems:
  * no 24bit modes. (maybe the hardware does not support)
  * pageflipping (in threeDKit) does not work.
  * no acceleration (is there a program that uses it anyway?).
*/


#include <stdlib.h>
#include <stdio.h>              /* for printf */
#include <string.h>             /* for memset */
//#include <sys/mman.h>         //SHARK
#include <fcntl.h>
#include <math.h>
#include <unistd.h>
#include "vga.h"
#include "libvga.h"
#include "driver.h"

/* New style driver interface. */
#include "timing.h"
#include "vgaregs.h"
#include "interface.h"
#include "nv3ref.h"
#include "nvreg.h"
#include "vgapci.h"

#define REG(i) (VGA_TOTAL_REGS+i)
#define NV3_TOTAL_REGS (VGA_TOTAL_REGS + 24 + 40 )

#define P_MIN 0

#define SetBitField(value,from,to) SetBF(to,GetBF(value,from))
#define SetBit(n) (1<<(n))
#define Set8Bits(value) ((value)&0xff)

#define GET15BITCOLOR(r,g,b) ((((r)&0xf8)<<7)|(((g)&0xf8)<<2)|((b)>>3))

#include "nv3io.c"

static int nv3_init(int, int, int);
static void nv3_unlock(void);

static int memory, chip, nvnum;
static int nv3_is_linear;
static CardSpecs *cardspecs;
static int PLL_INPUT_FREQ, MAXVCLOCK, M_MIN, M_MAX, P_MAX;

static unsigned long MMIOBASE, LINEARBASE;

enum {
   Riva128 = 0, RivaTNT, GEFORCE
};

static void nv3_setpage(int page)
{
__svgalib_outcrtc(0x1d,page << 1);
__svgalib_outcrtc(0x1e,page << 1);
}

static int __svgalib_nv3_inlinearmode(void)
{
return nv3_is_linear;
}

/* Fill in chipset specific mode information */

static void nv3_getmodeinfo(int mode, vga_modeinfo *modeinfo)
{
   
   if(modeinfo->colors==16)return;

   modeinfo->maxpixels = memory*1024/modeinfo->bytesperpixel;
   modeinfo->maxlogicalwidth = 4088;
   modeinfo->startaddressrange = memory * 1024 - 1;
   modeinfo->haveblit = 0;
   modeinfo->flags &= ~HAVE_RWPAGE;

   if (modeinfo->bytesperpixel >= 1) {
        modeinfo->flags |= CAPABLE_LINEAR;
        if (__svgalib_nv3_inlinearmode())
            modeinfo->flags |= IS_LINEAR | LINEAR_MODE;
   }
}

/* Read and save chipset-specific registers */

static int nv3_saveregs(unsigned char regs[])
{
    int i;
    nv3_unlock();               /* May be locked again by other programs (e.g. X) */

    regs[REG(0)] = __svgalib_incrtc(NV_PCRTC_REPAINT0);
    regs[REG(1)] = __svgalib_incrtc(NV_PCRTC_REPAINT1);
    regs[REG(2)] = __svgalib_incrtc(NV_PCRTC_EXTRA);
    regs[REG(3)] = __svgalib_incrtc(NV_PCRTC_PIXEL);
    regs[REG(4)] = __svgalib_incrtc(NV_PCRTC_HORIZ_EXTRA);
    regs[REG(5)] = __svgalib_incrtc(NV_PCRTC_FIFO_CONTROL);
    regs[REG(6)] = __svgalib_incrtc(NV_PCRTC_FIFO);
    regs[REG(7)] = __svgalib_incrtc(NV_PCRTC_SCREEN);

    *(uint32_t *)(regs+REG(8)) = v_readl(NV_PFB_CONFIG_0);
    *(uint32_t *)(regs+REG(12)) = v_readl(NV_PRAMDAC_VPLL_COEFF);
    *(uint32_t *)(regs+REG(16)) = v_readl(NV_PRAMDAC_PLL_COEFF_SELECT);
    *(uint32_t *)(regs+REG(20)) = v_readl(NV_PRAMDAC_GENERAL_CONTROL);
    *(uint32_t *)(regs+REG(56)) = v_readl(NV_PRAMDAC_GRCURSOR_START_POS);
    for(i=0x18;i<0x3A;i++)regs[84+i-0x18]=__svgalib_incrtc(i);
   
    return NV3_TOTAL_REGS - VGA_TOTAL_REGS;
}

/* Set chipset-specific registers */

static void nv3_setregs(const unsigned char regs[], int mode)
{
    nv3_unlock();               /* May be locked again by other programs (eg. X) */

   __svgalib_outcrtc(NV_PCRTC_REPAINT0,regs[REG(0)]);
   __svgalib_outcrtc(NV_PCRTC_REPAINT1,regs[REG(1)]);
   __svgalib_outcrtc(NV_PCRTC_EXTRA,regs[REG(2)]);
   __svgalib_outcrtc(NV_PCRTC_PIXEL,regs[REG(3)]);
   __svgalib_outcrtc(NV_PCRTC_HORIZ_EXTRA,regs[REG(4)]);
   __svgalib_outcrtc(NV_PCRTC_FIFO_CONTROL,regs[REG(5)]);
   __svgalib_outcrtc(NV_PCRTC_FIFO,regs[REG(6)]);
   if(chip>= GEFORCE)
       __svgalib_outcrtc(NV_PCRTC_SCREEN,regs[REG(7)]);

   __svgalib_outcrtc(0x1c,regs[88]); /* this enables banking at 0xa0000 */
   __svgalib_outcrtc(0x1d,regs[89]);
   __svgalib_outcrtc(0x1e,regs[90]);
   __svgalib_outcrtc(0x30,regs[108]);
   __svgalib_outcrtc(0x31,regs[109]);
   __svgalib_outcrtc(0x39,regs[117]);

   v_writel(*(uint32_t *)(regs+REG(8)), NV_PFB_CONFIG_0);

   v_writel(*(uint32_t *)(regs+REG(12)), NV_PRAMDAC_VPLL_COEFF);
   v_writel(*(uint32_t *)(regs+REG(16)), NV_PRAMDAC_PLL_COEFF_SELECT);
   v_writel(*(uint32_t *)(regs+REG(20)), NV_PRAMDAC_GENERAL_CONTROL);
   v_writel(*(uint32_t *)(regs+REG(56)), NV_PRAMDAC_GRCURSOR_START_POS);
}


/* Return nonzero if mode is available */

static int nv3_modeavailable(int mode)
{
    struct info *info;
    ModeTiming *modetiming;
    ModeInfo *modeinfo;

    printk(KERN_INFO "Test Mode...\n");
   
    if (IS_IN_STANDARD_VGA_DRIVER(mode))
        return __svgalib_vga_driverspecs.modeavailable(mode);

    info = &__svgalib_infotable[mode];
    if (memory * 1024 < info->ydim * info->xbytes)
        return 0;
   
    modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode);

    if(modeinfo->bitsPerPixel==24) {
        free(modeinfo);
        return 0;  
    }

    printk(KERN_INFO "Test Timing...\n");
   
    modetiming = malloc(sizeof(ModeTiming));
   
    if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) {
        printk(KERN_INFO "Test Mode Failed !\n");      
        free(modetiming);
        free(modeinfo);
        return 0;
    }

    free(modetiming);
    free(modeinfo);
    return SVGADRV;
}

static int CalcVClock(int clockIn,int *clockOut,int *mOut,
                                         int *nOut,int *pOut);

static int CalculateCRTC(ModeTiming *mode, ModeInfo *modeinfo, unsigned char *moderegs)
{
  int bpp=modeinfo->bitsPerPixel/8,
      horizDisplay    = (mode->CrtcHDisplay/8)   - 1,
      horizStart      = (mode->CrtcHSyncStart/8) - 0,
      horizEnd        = (mode->CrtcHSyncEnd/8)   - 0,
      horizTotal      = (mode->CrtcHTotal/8)     - 5,
      horizBlankStart = (mode->CrtcHDisplay/8)   - 1,
      horizBlankEnd   = (mode->CrtcHTotal/8)     - 1,
      vertDisplay     = mode->CrtcVDisplay       - 1,
      vertStart       = mode->CrtcVSyncStart     - 1,
      vertEnd         = mode->CrtcVSyncEnd       - 1,
      vertTotal       = mode->CrtcVTotal         - 2,
      vertBlankStart  =  mode->CrtcVDisplay      - 1,
      vertBlankEnd    =  mode->CrtcVTotal        - 1;

  if(mode->flags & INTERLACED) vertTotal |= 1;

  /* Calculate correct value for offset register */
  moderegs[0x13]=((modeinfo->width/8)*bpp)&0xff;

  /* Extra bits for CRTC offset register */
  moderegs[REG(0)]=
    SetBitField((modeinfo->width/8)*bpp,10:8,7:5);

  /* The NV3 manuals states that for native modes, there should be no
   * borders. This code should also be tidied up to use symbolic names
   */
   
  moderegs[0x0]=Set8Bits(horizTotal);
  moderegs[0x1]=Set8Bits(horizDisplay);
  moderegs[0x2]=Set8Bits(horizBlankStart);
  moderegs[0x3]=SetBitField(horizBlankEnd,4:0,4:0) | SetBit(7);
  moderegs[0x4]=Set8Bits(horizStart);
  moderegs[0x5]=SetBitField(horizBlankEnd,5:5,7:7)|
                     SetBitField(horizEnd,4:0,4:0);
  moderegs[0x6]=SetBitField(vertTotal,7:0,7:0);

  moderegs[0x7]=SetBitField(vertTotal,8:8,0:0)|
                     SetBitField(vertDisplay,8:8,1:1)|
                     SetBitField(vertStart,8:8,2:2)|
                     SetBitField(vertBlankStart,8:8,3:3)|
                     SetBit(4)|
                     SetBitField(vertTotal,9:9,5:5)|
                     SetBitField(vertDisplay,9:9,6:6)|
                     SetBitField(vertStart,9:9,7:7);

  moderegs[0x9]= SetBitField(vertBlankStart,9:9,5:5) | SetBit(6);
  moderegs[0x10]= Set8Bits(vertStart);
  moderegs[0x11]= SetBitField(vertEnd,3:0,3:0) | SetBit(5);
  moderegs[0x12]= Set8Bits(vertDisplay);
  moderegs[0x15]= Set8Bits(vertBlankStart);
  moderegs[0x16]= Set8Bits(vertBlankEnd);

 moderegs[REG(2)]  = SetBitField(horizBlankEnd,6:6,4:4)
                  | SetBitField(vertBlankStart,10:10,3:3)
                  | SetBitField(vertStart,10:10,2:2)
                  | SetBitField(vertDisplay,10:10,1:1)
                  | SetBitField(vertTotal,10:10,0:0);

 moderegs[REG(4)] = SetBitField(horizTotal,8:8,0:0)
                  | SetBitField(horizDisplay,8:8,1:1)
                  | SetBitField(horizBlankStart,8:8,2:2)
                  | SetBitField(horizStart,8:8,3:3);

 moderegs[REG(7)] = SetBitField(vertTotal,11:11,0:0)
                    | SetBitField(vertDisplay,11:11,2:2)
                    | SetBitField(vertStart,11:11,4:4)
                    | SetBitField(vertBlankStart,11:11,6:6);

  if(mode->flags & DOUBLESCAN) moderegs[0x9]|=0x80;
 
  /* I think this should be SetBitField(horizTotal,8:8,0:0), but this
   * doesn't work apparently. Why 260 ? 256 would make sense.
   */

  if(mode->flags & INTERLACED) {
      horizTotal=(horizTotal>>1)& ~1;
      moderegs[117]=horizTotal & 0xff;      
      moderegs[REG(4)] |= SetBitField(horizTotal,8:8,4:4);
  } else {
      moderegs[117]=255;
  }

  return 1;
}

/* Set a mode */

/* Local, called by nv3_setmode(). */

static void nv3_initializemode(unsigned char *moderegs,
                            ModeTiming * modetiming, ModeInfo * modeinfo, int mode)
{
    long k;
    unsigned int config0=0;
   
    int m,n,p;
    int clockIn=modetiming->pixelClock;
    int clockOut;
    int pixelDepth;
 
    nv3_saveregs(moderegs);

    __svgalib_setup_VGA_registers(moderegs, modetiming, modeinfo);

    CalcVClock(clockIn,&clockOut,&m,&n,&p);

    *(unsigned int *)(moderegs+REG(12)) = PRAMDAC_Val(VPLL_COEFF_NDIV,n) |
                                          PRAMDAC_Val(VPLL_COEFF_MDIV,m) |
                                          PRAMDAC_Val(VPLL_COEFF_PDIV,p);

    CalculateCRTC(modetiming,modeinfo,moderegs);

    moderegs[REG(1)] = PCRTC_Val(REPAINT1_LARGE_SCREEN,modetiming->CrtcHDisplay<1280);

/* The new xfree driver (from nVidia) calculates those in some
   twisted way, but I leave it for now */

    moderegs[REG(5)]=0x83;
    if(modetiming->pixelClock*modeinfo->bytesPerPixel>720000) {
        moderegs[REG(6)]=0x2f;
    }

  /* PixelFormat controls how many bits per pixel.
   * There is another register in the
   * DAC which controls if mode is 5:5:5 or 5:6:5
   */

    pixelDepth=(modeinfo->bitsPerPixel+1)/8;
    if(pixelDepth>3) pixelDepth=3;
    moderegs[REG(3)]=pixelDepth;
    if(modetiming->flags & TVMODE) {
        moderegs[REG(3)]|=0x80;
        if(modetiming->flags & TVPAL) moderegs[REG(3)]|=0x40;
    };

    *(unsigned int *)(moderegs+REG(20))=
        PRAMDAC_Def(GENERAL_CONTROL_IDC_MODE,GAMMA)|
        PRAMDAC_Val(GENERAL_CONTROL_565_MODE,modeinfo->greenWeight==6)|
        PRAMDAC_Def(GENERAL_CONTROL_TERMINATION,37OHM)|
        ((modeinfo->bitsPerPixel>8) ?
            PRAMDAC_Def(GENERAL_CONTROL_BPC,8BITS) :
            PRAMDAC_Def(GENERAL_CONTROL_BPC,6BITS)) | PRAMDAC_Def(GENERAL_CONTROL_VGA_STATE,SEL);
            /* Not sure about this */

    switch(chip){
      case Riva128:
          config0=PFB_Val(CONFIG_0_RESOLUTION,((modeinfo->lineWidth+31)/32))|
                  PFB_Val(CONFIG_0_PIXEL_DEPTH,pixelDepth)|
                  PFB_Def(CONFIG_0_TILING,DISABLED);
          k=PRAMDAC_Def(PLL_COEFF_SELECT_MPLL_SOURCE,PROG)|
            PRAMDAC_Def(PLL_COEFF_SELECT_VPLL_SOURCE,PROG)|
            PRAMDAC_Def(PLL_COEFF_SELECT_VCLK_RATIO,DB2);
          moderegs[REG(1)] |= PCRTC_Def(REPAINT1_PALETTE_WIDTH,6BITS);
          break;
      case RivaTNT:
          config0=0x1114;
          k=0x10000700;
          break;
      case GEFORCE:
      default:
          config0=*(unsigned int *)(moderegs+REG(8));
          k=0x10000700;
          break;
   };

   *(unsigned int *)(moderegs+REG(16))=k;
   *(unsigned int *)(moderegs+REG(8))=config0;

   moderegs[88]=28;
   moderegs[109]&=0xfe; /* hide cursor */

   nv3_is_linear=0;

return ;
}


int nv3_setmode(int mode, int prv_mode)
{
    unsigned char *moderegs;
    ModeTiming *modetiming;
    ModeInfo *modeinfo;
    int i;

    if (IS_IN_STANDARD_VGA_DRIVER(mode)) {
       
        unsigned int k;
           
        printk(KERN_INFO "Standard VGA Mode\n");

        if(chip==Riva128)
            v_writel(0x00000100, NV_PRAMDAC_PLL_COEFF_SELECT);
            else v_writel(0x00000500, NV_PRAMDAC_PLL_COEFF_SELECT);
        __svgalib_outcrtc(NV_PCRTC_REPAINT0,0);
        __svgalib_outcrtc(NV_PCRTC_REPAINT1,0x3d);
        __svgalib_outcrtc(NV_PCRTC_EXTRA,0);
        __svgalib_outcrtc(NV_PCRTC_PIXEL,0);
        __svgalib_outcrtc(NV_PCRTC_HORIZ_EXTRA,0);
        __svgalib_outcrtc(NV_PCRTC_FIFO_CONTROL,0x83);
        __svgalib_outcrtc(0x1c,0x18);
        __svgalib_outcrtc(0x1d,0);
        __svgalib_outcrtc(0x1e,0);
        __svgalib_outcrtc(0x30,0);
        __svgalib_outcrtc(0x31,0);
        k =  v_readl(NV_PRAMDAC_GENERAL_CONTROL);
        k &= ~0x00100000;
        v_writel(k, NV_PRAMDAC_GENERAL_CONTROL);

        return __svgalib_vga_driverspecs.setmode(mode, prv_mode);
    }

    if (!nv3_modeavailable(mode))
        return 1;

    printk(KERN_INFO "Mode Available !\nStart Set Mode...\n");
   
    modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode);

    modetiming = malloc(sizeof(ModeTiming));
    if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) {
        free(modetiming);
        free(modeinfo);
        return 1;
    }

    moderegs = malloc(NV3_TOTAL_REGS);

    printk(KERN_INFO "Start Init Mode...\n");
   
    nv3_initializemode(moderegs, modetiming, modeinfo, mode);
    free(modetiming);

    __svgalib_setregs(moderegs);        /* Set standard regs. */
    nv3_setregs(moderegs, mode);        /* Set extended regs. */
    free(moderegs);

    __svgalib_InitializeAcceleratorInterface(modeinfo);

    for(i=0;i<256;i++)vga_setpalette(i,i,i,i);
    free(modeinfo);
    return 0;
}

/* Unlock chipset-specific registers */

static void nv3_unlock(void)
{
    if(chip!=Riva128) {
        __svgalib_nv3_outcrtc(0x11,__svgalib_incrtc(0x11)&0x7f);
        __svgalib_nv3_outcrtc(0x1f, UNLOCK_EXT_MAGIC);
    } else {
//        __svgalib_outcrtc(0x11,__svgalib_incrtc(0x11)&0x7f);
        __svgalib_outseq(LOCK_EXT_INDEX,UNLOCK_EXT_MAGIC);    
    }
}

/* Relock chipset-specific registers */
/* (currently not used) */

static void nv3_lock(void)
{
    __svgalib_outseq(LOCK_EXT_INDEX,UNLOCK_EXT_MAGIC+1);    

}

/* Indentify chipset, initialize and return non-zero if detected */

int nv3_test(void)
{  unsigned long buf[64];
   int found=0;

   MMIOBASE=0; /* let nv3_init() find those */
   LINEARBASE=0;
   nv3_init(0,0,0);
   return 1;
}

/* No r/w paging - I guess it's possible, but is it useful? */
static void nv3_setrdpage(int page)
{
}
static void nv3_setwrpage(int page)
{
}

/* Set display start address (not for 16 color modes) */

static void nv3_setdisplaystart(int address)
{  unsigned char byte;
    int pan;

  pan=(address&3)<<1;
  address=address >> 2;
  __svgalib_outcrtc(0x0d,address&0xff);
  __svgalib_outcrtc(0x0c,(address>>8)&0xff);
  byte=__svgalib_incrtc(NV_PCRTC_REPAINT0) & 0xe0;
  __svgalib_outcrtc(NV_PCRTC_REPAINT0,((address>>16)&0x1f)|byte);
  byte=__svgalib_incrtc(0x2D) & ~0x60;
  __svgalib_outcrtc(0x2D,((address>>16)&0x60)|byte);

  byte = __svgalib_inis1();
  __svgalib_outatt(0x13, pan);
}

/* Set logical scanline length (usually multiple of 8) */

static void nv3_setlogicalwidth(int width)
{  int byte ;

  __svgalib_outcrtc(0x13,(width >> 3)&0xff);
  byte=__svgalib_incrtc(NV_PCRTC_REPAINT0) & 0x1f;
  __svgalib_outcrtc(NV_PCRTC_REPAINT0,SetBitField(width,13:11,7:5)|byte);

}

static int nv3_linear(int op, int param)
{
if (op==LINEAR_ENABLE){ nv3_is_linear=1; return 0;}
if (op==LINEAR_DISABLE){ nv3_is_linear=0; return 0;}
if (op==LINEAR_QUERY_BASE) { return LINEARBASE ;}
if (op == LINEAR_QUERY_RANGE || op == LINEAR_QUERY_GRANULARITY) return 0;               /* No granularity or range. */
    else return -1;             /* Unknown function. */
}

static int nv3_cursor( int cmd, int p1, int p2, int p3, int p4, void *p5) {
    unsigned char *b1, *b2;
    unsigned short *b3;
    unsigned int i, j, k, l, c0, c1;
   
    switch(cmd){
        case CURSOR_INIT:
            return 1;
        case CURSOR_HIDE:
            __svgalib_outcrtc(0x31,__svgalib_incrtc(0x31)&0xfe); /* disable cursor */
            break;
        case CURSOR_SHOW:
            __svgalib_outcrtc(0x31,__svgalib_incrtc(0x31)|1); /* enable cursor */
            break;
        case CURSOR_POSITION:
            v_writel(p1+(p2<<16), NV_PRAMDAC_GRCURSOR_START_POS);
            break;
        case CURSOR_SELECT:
            i=memory/2-(p1+1);
            if (chip==Riva128) {
                __svgalib_outcrtc(0x31,(__svgalib_incrtc(0x31)&7)|(((~i)&0x1f)<<3));
            } else {
                __svgalib_outcrtc(0x31,(__svgalib_incrtc(0x31)&3)|(((~i)&0x3f)<<2));
            }
#if 0
            __svgalib_outcrtc(0x30,((~i)&0x3fc0)>>6);
#else
            __svgalib_outcrtc(0x30,0);
#endif
            break;
        case CURSOR_IMAGE:
            i=memory/2-(p1+1);
            i=i*2048;
            switch(p2) {
                case 0: /* X11 format, 32x32 */
                    b3=malloc(2048);
                    b1=(unsigned char *)p5;
                    b2=b1+128;
                    c0=0x8000|GET15BITCOLOR((p3>>16)&0xff,(p3>>8)&0xff,p3&0xff);
                    c1=0x8000|GET15BITCOLOR((p4>>16)&0xff,(p4>>8)&0xff,p4&0xff);
                    l=992;
                    for(k=0;k<128;k++) {
                        int cc1=*(b1+k);
                        int cc2=*(b2+k);
                        for(j=0;j<8;j++) {
                            if(!(cc2&0x80)) *(b3+l)=0; else if (cc1&0x80)
                                *(b3+l)=c1; else *(b3+l)=c0;
                            l++;
                            if((l&0x1f)==0)l-=64;
                            cc2<<=1;
                            cc1<<=1;
                        }
                    }
                    memcpy(LINEAR_POINTER+i,b3,2048);
                    free(b3);
                    break;
                case 1: /* nvidia 1555 format  32x32 */
                    memcpy(LINEAR_POINTER+i,p5,2048);
                    break;
            }
            break;
    }
    return 0;
}      

static int nv3_match_programmable_clock(int clock)
{
return clock ;
}
static int nv3_map_clock(int bpp, int clock)
{
return clock ;
}
static int nv3_map_horizontal_crtc(int bpp, int pixelclock, int htiming)
{
return htiming;
}
/* Function table (exported) */

DriverSpecs __svgalib_nv3_driverspecs =
{
    nv3_saveregs,
    nv3_setregs,
    nv3_unlock,
    nv3_lock,
    nv3_test,
    nv3_init,
    nv3_setpage,
    nv3_setrdpage,
    nv3_setwrpage,
    nv3_setmode,
    nv3_modeavailable,
    nv3_setdisplaystart,
    nv3_setlogicalwidth,
    nv3_getmodeinfo,
    0,                          /* old blit funcs */
    0,
    0,
    0,
    0,
    0,                          /* ext_set */
    0,                          /* accel */
    nv3_linear,
    0,                          /* accelspecs, filled in during init. */
    0,
    nv3_cursor
};

/* Initialize chipset (called after detection) */

static int nv3_init(int force, int par1, int par2) //SHARK
{  
    char *archs[3]={"Riva128",
                    "RivaTNT",
                    "GeForce"};
    int flags;
   
    flags=0;
    if(MMIOBASE==0) {
       unsigned long buf[64];
       int found;
     
       printk(KERN_INFO "Init NVidia card: scan pci bus\n");
       
       found=__svgalib_pci_find_vendor_vga(0x12d2,buf,0);
       if (found) {
          found=__svgalib_pci_find_vendor_vga(0x10de,buf,0);
          if(found) {
            printk(KERN_INFO "Error: NVidia card not found\n");
            return 0;
          }
       }
     
       switch((buf[0]>>20)&0xff){
          case 0x1:
             chip=Riva128;
             nvnum=3;
             break;
          case 0x2:
          case 0xA:
             chip=RivaTNT;
             switch((buf[0]>>16)&0xff){
                 case 0x20:
                     nvnum=4;
                     break;
                 case 0x2c:
                 case 0x2d:
                 case 0x2e:
                 case 0x2f:
                     nvnum=6;
                     break;
                 default:
                     nvnum=5;
             }
             break;
          case 0x10:
          case 0x15:
             chip=GEFORCE;
             nvnum=(buf[0]>>20)&0xff;
             break;
          case 0x11:
          case 0x17:
          case 0x1A:
          case 0x20:
          case 0x25:
          default:
             flags = NO_INTERLACE;
             chip=GEFORCE;
             nvnum=(buf[0]>>20)&0xff;
             break;
       };
       MMIOBASE=buf[4]&0xffffff00;
       LINEARBASE=buf[5]&0xffffff00;
    };
   
    printk(KERN_INFO "NVidia card found ! BASE_ADDR: %.8x TYPE: %s (NV%.8x)\n",MMIOBASE,archs[chip],nvnum);
   
    if (force) {
        memory = par1;
        chip = par2;
    };

    __svgalib_modeinfo_linearset |= IS_LINEAR;

    __svgalib_mmio_base=MMIOBASE;
    __svgalib_mmio_size=8*1024*1024;

    map_mmio();
   
    if(!force){
       int boot0;
       
       boot0=v_readl(NV_PFB_BOOT_0);
       switch(chip){
          case Riva128:
                 if(boot0&0x20)memory=8192; else memory=1024<<(boot0&3);
                 if(memory==1024)memory=8192;
                 break;
          case RivaTNT:
                 memory=2048<<(boot0&3);
                 if(memory==2048)memory=32768;
                 break;
          case GEFORCE:
                 memory=(v_readl(NV_PFB_BOOT_10)>>10) & 0x3fc00;
                 if(memory<8192)memory=8192; // do this later
                 break;
       }
    }

    nv3_mapio();
    nv3_unlock();

    {
       int temp;
       
       temp=v_readl(NV_PEXTDEV_0);
       switch(chip){
          case Riva128:
             PLL_INPUT_FREQ= (temp&0x20) ? 14318 : 13500;
             MAXVCLOCK=256000;
             P_MAX=4;// XFree say 3, but 4 works on my Riva128
             if(PLL_INPUT_FREQ==13500)M_MAX=12; else M_MAX=13;
             M_MIN=M_MAX-5;
             break;
          case RivaTNT:
             PLL_INPUT_FREQ= (temp&0x40) ? 14318 : 13500;
             MAXVCLOCK=350000;
             P_MAX=4;
             if(PLL_INPUT_FREQ==13500)M_MAX=13; else M_MAX=14;
             M_MIN=M_MAX-6;
             break;
          case GEFORCE:
          default:
             PLL_INPUT_FREQ= (temp&0x40  ) ? 14318 : 13500;
             if(nvnum==0x17 ||  nvnum==0x25) {
                 if(temp&0x400000) PLL_INPUT_FREQ=27000;
             }
             MAXVCLOCK=350000;
             P_MAX=4;
             if(PLL_INPUT_FREQ==13500)M_MAX=13; else M_MAX=14;
             M_MIN=M_MAX-6;
             break;
       };
    };

    cardspecs = malloc(sizeof(CardSpecs));
    cardspecs->videoMemory = memory;
    if(chip==Riva128) {
       cardspecs->maxPixelClock4bpp = 75000;   
       cardspecs->maxPixelClock8bpp = 230000;  
       cardspecs->maxPixelClock16bpp = 230000; 
       cardspecs->maxPixelClock24bpp = 0;
       cardspecs->maxPixelClock32bpp = 230000;
    } else {
       cardspecs->maxPixelClock4bpp = 75000;   
       cardspecs->maxPixelClock8bpp = 350000;  
       cardspecs->maxPixelClock16bpp = 350000; 
       cardspecs->maxPixelClock24bpp = 0;
       cardspecs->maxPixelClock32bpp = 350000;    
    }
    cardspecs->flags = flags | CLOCK_PROGRAMMABLE ;
    cardspecs->maxHorizontalCrtc = 4080;
    cardspecs->maxPixelClock4bpp = 0;
    cardspecs->nClocks =0;
    cardspecs->clocks = NULL;
    cardspecs->mapClock = nv3_map_clock;
    cardspecs->mapHorizontalCrtc = nv3_map_horizontal_crtc;
    cardspecs->matchProgrammableClock=nv3_match_programmable_clock;
    __svgalib_driverspecs = &__svgalib_nv3_driverspecs;
   
    __svgalib_banked_mem_base=0xa0000;
    __svgalib_banked_mem_size=0x10000;
    __svgalib_linear_mem_base=LINEARBASE;
    __svgalib_linear_mem_size=memory*0x400;
   
    printk(KERN_INFO "NVidia Card Initialized ! LIN_ADDR:%.8x LIN_SIZE:%d\n",__svgalib_linear_mem_base,__svgalib_linear_mem_size);
   
    sleep(4);
   
    return 0;
   
}

/*
 * Calculate the Video Clock parameters for the PLL.
 */

static int CalcVClock
(
    int           clockIn,
    int          *clockOut,
    int          *mOut,
    int          *nOut,
    int          *pOut
)
{
    unsigned DeltaNew, DeltaOld;
    unsigned VClk, Freq;
    unsigned M, N, P;
   
    DeltaOld = 0xFFFFFFFF;

    VClk     = (unsigned)clockIn;
   
    for (P = 0; P <= P_MAX; P ++)
    {
        Freq = VClk << P;
        if ((Freq >= 128000) && (Freq <= MAXVCLOCK))
        {
            for (M = M_MIN; M <= M_MAX; M++)
            {
                N    = ((VClk<<P) * M + PLL_INPUT_FREQ/2) / PLL_INPUT_FREQ;
                Freq = (PLL_INPUT_FREQ * N / M) >> P;
                if (Freq > VClk)
                    DeltaNew = Freq - VClk;
                else
                    DeltaNew = VClk - Freq;
                if ((DeltaNew < DeltaOld) && (N<256))
                {
                    *mOut     = M;
                    *nOut     = N;
                    *pOut     = P;
                    *clockOut = Freq;
                    DeltaOld  = DeltaNew;
                }
            }
        }
    }
    return (DeltaOld != 0xFFFFFFFF);
}