in fbdev/savage/savagefb_driver.c [968:1192]
static int savagefb_decode_var(struct fb_var_screeninfo *var,
struct savagefb_par *par,
struct savage_reg *reg)
{
struct xtimings timings;
int width, dclk, i, j; /*, refresh; */
unsigned int m, n, r;
unsigned char tmp = 0;
unsigned int pixclock = var->pixclock;
DBG("savagefb_decode_var");
memset(&timings, 0, sizeof(timings));
if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */
timings.Clock = 1000000000 / pixclock;
if (timings.Clock < 1) timings.Clock = 1;
timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
timings.HDisplay = var->xres;
timings.HSyncStart = timings.HDisplay + var->right_margin;
timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
timings.HTotal = timings.HSyncEnd + var->left_margin;
timings.VDisplay = var->yres;
timings.VSyncStart = timings.VDisplay + var->lower_margin;
timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
timings.VTotal = timings.VSyncEnd + var->upper_margin;
timings.sync = var->sync;
par->depth = var->bits_per_pixel;
par->vwidth = var->xres_virtual;
if (var->bits_per_pixel == 16 && par->chip == S3_SAVAGE3D) {
timings.HDisplay *= 2;
timings.HSyncStart *= 2;
timings.HSyncEnd *= 2;
timings.HTotal *= 2;
}
/*
* This will allocate the datastructure and initialize all of the
* generic VGA registers.
*/
vgaHWInit(var, par, &timings, reg);
/* We need to set CR67 whether or not we use the BIOS. */
dclk = timings.Clock;
reg->CR67 = 0x00;
switch(var->bits_per_pixel) {
case 8:
if ((par->chip == S3_SAVAGE2000) && (dclk >= 230000))
reg->CR67 = 0x10; /* 8bpp, 2 pixels/clock */
else
reg->CR67 = 0x00; /* 8bpp, 1 pixel/clock */
break;
case 15:
if (S3_SAVAGE_MOBILE_SERIES(par->chip) ||
((par->chip == S3_SAVAGE2000) && (dclk >= 230000)))
reg->CR67 = 0x30; /* 15bpp, 2 pixel/clock */
else
reg->CR67 = 0x20; /* 15bpp, 1 pixels/clock */
break;
case 16:
if (S3_SAVAGE_MOBILE_SERIES(par->chip) ||
((par->chip == S3_SAVAGE2000) && (dclk >= 230000)))
reg->CR67 = 0x50; /* 16bpp, 2 pixel/clock */
else
reg->CR67 = 0x40; /* 16bpp, 1 pixels/clock */
break;
case 24:
reg->CR67 = 0x70;
break;
case 32:
reg->CR67 = 0xd0;
break;
}
/*
* Either BIOS use is disabled, or we failed to find a suitable
* match. Fall back to traditional register-crunching.
*/
vga_out8(0x3d4, 0x3a, par);
tmp = vga_in8(0x3d5, par);
if (1 /*FIXME:psav->pci_burst*/)
reg->CR3A = (tmp & 0x7f) | 0x15;
else
reg->CR3A = tmp | 0x95;
reg->CR53 = 0x00;
reg->CR31 = 0x8c;
reg->CR66 = 0x89;
vga_out8(0x3d4, 0x58, par);
reg->CR58 = vga_in8(0x3d5, par) & 0x80;
reg->CR58 |= 0x13;
reg->SR15 = 0x03 | 0x80;
reg->SR18 = 0x00;
reg->CR43 = reg->CR45 = reg->CR65 = 0x00;
vga_out8(0x3d4, 0x40, par);
reg->CR40 = vga_in8(0x3d5, par) & ~0x01;
reg->MMPR0 = 0x010400;
reg->MMPR1 = 0x00;
reg->MMPR2 = 0x0808;
reg->MMPR3 = 0x08080810;
SavageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);
/* m = 107; n = 4; r = 2; */
if (par->MCLK <= 0) {
reg->SR10 = 255;
reg->SR11 = 255;
} else {
common_calc_clock(par->MCLK, 1, 1, 31, 0, 3, 135000, 270000,
®->SR11, ®->SR10);
/* reg->SR10 = 80; // MCLK == 286000 */
/* reg->SR11 = 125; */
}
reg->SR12 = (r << 6) | (n & 0x3f);
reg->SR13 = m & 0xff;
reg->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
if (var->bits_per_pixel < 24)
reg->MMPR0 -= 0x8000;
else
reg->MMPR0 -= 0x4000;
if (timings.interlaced)
reg->CR42 = 0x20;
else
reg->CR42 = 0x00;
reg->CR34 = 0x10; /* display fifo */
i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) |
((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) |
((((timings.HSyncStart >> 3) - 1) & 0x100) >> 6) |
((timings.HSyncStart & 0x800) >> 7);
if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 64)
i |= 0x08;
if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32)
i |= 0x20;
j = (reg->CRTC[0] + ((i & 0x01) << 8) +
reg->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
if (j - (reg->CRTC[4] + ((i & 0x10) << 4)) < 4) {
if (reg->CRTC[4] + ((i & 0x10) << 4) + 4 <=
reg->CRTC[0] + ((i & 0x01) << 8))
j = reg->CRTC[4] + ((i & 0x10) << 4) + 4;
else
j = reg->CRTC[0] + ((i & 0x01) << 8) + 1;
}
reg->CR3B = j & 0xff;
i |= (j & 0x100) >> 2;
reg->CR3C = (reg->CRTC[0] + ((i & 0x01) << 8)) / 2;
reg->CR5D = i;
reg->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) |
(((timings.VDisplay - 1) & 0x400) >> 9) |
(((timings.VSyncStart) & 0x400) >> 8) |
(((timings.VSyncStart) & 0x400) >> 6) | 0x40;
width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3;
reg->CR91 = reg->CRTC[19] = 0xff & width;
reg->CR51 = (0x300 & width) >> 4;
reg->CR90 = 0x80 | (width >> 8);
reg->MiscOutReg |= 0x0c;
/* Set frame buffer description. */
if (var->bits_per_pixel <= 8)
reg->CR50 = 0;
else if (var->bits_per_pixel <= 16)
reg->CR50 = 0x10;
else
reg->CR50 = 0x30;
if (var->xres_virtual <= 640)
reg->CR50 |= 0x40;
else if (var->xres_virtual == 800)
reg->CR50 |= 0x80;
else if (var->xres_virtual == 1024)
reg->CR50 |= 0x00;
else if (var->xres_virtual == 1152)
reg->CR50 |= 0x01;
else if (var->xres_virtual == 1280)
reg->CR50 |= 0xc0;
else if (var->xres_virtual == 1600)
reg->CR50 |= 0x81;
else
reg->CR50 |= 0xc1; /* Use GBD */
if (par->chip == S3_SAVAGE2000)
reg->CR33 = 0x08;
else
reg->CR33 = 0x20;
reg->CRTC[0x17] = 0xeb;
reg->CR67 |= 1;
vga_out8(0x3d4, 0x36, par);
reg->CR36 = vga_in8(0x3d5, par);
vga_out8(0x3d4, 0x68, par);
reg->CR68 = vga_in8(0x3d5, par);
reg->CR69 = 0;
vga_out8(0x3d4, 0x6f, par);
reg->CR6F = vga_in8(0x3d5, par);
vga_out8(0x3d4, 0x86, par);
reg->CR86 = vga_in8(0x3d5, par);
vga_out8(0x3d4, 0x88, par);
reg->CR88 = vga_in8(0x3d5, par) | 0x08;
vga_out8(0x3d4, 0xb0, par);
reg->CRB0 = vga_in8(0x3d5, par) | 0x80;
return 0;
}