in fbdev/sis/sis_main.c [4631:4881]
static int sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
{
unsigned int buswidth, ranksize, channelab, mapsize;
int i, j, k, l, status;
u8 reg, sr14;
static const u8 dramsr13[12 * 5] = {
0x02, 0x0e, 0x0b, 0x80, 0x5d,
0x02, 0x0e, 0x0a, 0x40, 0x59,
0x02, 0x0d, 0x0b, 0x40, 0x4d,
0x02, 0x0e, 0x09, 0x20, 0x55,
0x02, 0x0d, 0x0a, 0x20, 0x49,
0x02, 0x0c, 0x0b, 0x20, 0x3d,
0x02, 0x0e, 0x08, 0x10, 0x51,
0x02, 0x0d, 0x09, 0x10, 0x45,
0x02, 0x0c, 0x0a, 0x10, 0x39,
0x02, 0x0d, 0x08, 0x08, 0x41,
0x02, 0x0c, 0x09, 0x08, 0x35,
0x02, 0x0c, 0x08, 0x04, 0x31
};
static const u8 dramsr13_4[4 * 5] = {
0x02, 0x0d, 0x09, 0x40, 0x45,
0x02, 0x0c, 0x09, 0x20, 0x35,
0x02, 0x0c, 0x08, 0x10, 0x31,
0x02, 0x0b, 0x08, 0x08, 0x21
};
/* Enable linear mode, disable 0xa0000 address decoding */
/* We disable a0000 address decoding, because
* - if running on x86, if the card is disabled, it means
* that another card is in the system. We don't want
* to interphere with that primary card's textmode.
* - if running on non-x86, there usually is no VGA window
* at a0000.
*/
SiS_SetRegOR(SISSR, 0x20, (0x80 | 0x04));
/* Need to map max FB size for finding out about RAM size */
mapsize = ivideo->video_size;
sisfb_post_map_vram(ivideo, &mapsize, 32);
if(!ivideo->video_vbase) {
printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
SiS_SetReg(SISSR, 0x13, 0x35);
SiS_SetReg(SISSR, 0x14, 0x41);
/* TODO */
return -ENOMEM;
}
/* Non-interleaving */
SiS_SetReg(SISSR, 0x15, 0x00);
/* No tiling */
SiS_SetReg(SISSR, 0x1c, 0x00);
if(ivideo->chip == XGI_20) {
channelab = 1;
reg = SiS_GetReg(SISCR, 0x97);
if(!(reg & 0x01)) { /* Single 32/16 */
buswidth = 32;
SiS_SetReg(SISSR, 0x13, 0xb1);
SiS_SetReg(SISSR, 0x14, 0x52);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x02;
if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
goto bail_out;
SiS_SetReg(SISSR, 0x13, 0x31);
SiS_SetReg(SISSR, 0x14, 0x42);
sisfb_post_xgi_delay(ivideo, 1);
if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
goto bail_out;
buswidth = 16;
SiS_SetReg(SISSR, 0x13, 0xb1);
SiS_SetReg(SISSR, 0x14, 0x41);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x01;
if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
goto bail_out;
else
SiS_SetReg(SISSR, 0x13, 0x31);
} else { /* Dual 16/8 */
buswidth = 16;
SiS_SetReg(SISSR, 0x13, 0xb1);
SiS_SetReg(SISSR, 0x14, 0x41);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x01;
if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
goto bail_out;
SiS_SetReg(SISSR, 0x13, 0x31);
SiS_SetReg(SISSR, 0x14, 0x31);
sisfb_post_xgi_delay(ivideo, 1);
if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
goto bail_out;
buswidth = 8;
SiS_SetReg(SISSR, 0x13, 0xb1);
SiS_SetReg(SISSR, 0x14, 0x30);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x00;
if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
goto bail_out;
else
SiS_SetReg(SISSR, 0x13, 0x31);
}
} else { /* XGI_40 */
reg = SiS_GetReg(SISCR, 0x97);
if(!(reg & 0x10)) {
reg = SiS_GetReg(SISSR, 0x39);
reg >>= 1;
}
if(reg & 0x01) { /* DDRII */
buswidth = 32;
if(ivideo->revision_id == 2) {
channelab = 2;
SiS_SetReg(SISSR, 0x13, 0xa1);
SiS_SetReg(SISSR, 0x14, 0x44);
sr14 = 0x04;
sisfb_post_xgi_delay(ivideo, 1);
if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
goto bail_out;
SiS_SetReg(SISSR, 0x13, 0x21);
SiS_SetReg(SISSR, 0x14, 0x34);
if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
goto bail_out;
channelab = 1;
SiS_SetReg(SISSR, 0x13, 0xa1);
SiS_SetReg(SISSR, 0x14, 0x40);
sr14 = 0x00;
if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
goto bail_out;
SiS_SetReg(SISSR, 0x13, 0x21);
SiS_SetReg(SISSR, 0x14, 0x30);
} else {
channelab = 3;
SiS_SetReg(SISSR, 0x13, 0xa1);
SiS_SetReg(SISSR, 0x14, 0x4c);
sr14 = 0x0c;
sisfb_post_xgi_delay(ivideo, 1);
if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
goto bail_out;
channelab = 2;
SiS_SetReg(SISSR, 0x14, 0x48);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x08;
if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
goto bail_out;
SiS_SetReg(SISSR, 0x13, 0x21);
SiS_SetReg(SISSR, 0x14, 0x3c);
sr14 = 0x0c;
if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
channelab = 3;
} else {
channelab = 2;
SiS_SetReg(SISSR, 0x14, 0x38);
sr14 = 0x08;
}
}
sisfb_post_xgi_delay(ivideo, 1);
} else { /* DDR */
buswidth = 64;
if(ivideo->revision_id == 2) {
channelab = 1;
SiS_SetReg(SISSR, 0x13, 0xa1);
SiS_SetReg(SISSR, 0x14, 0x52);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x02;
if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
goto bail_out;
SiS_SetReg(SISSR, 0x13, 0x21);
SiS_SetReg(SISSR, 0x14, 0x42);
} else {
channelab = 2;
SiS_SetReg(SISSR, 0x13, 0xa1);
SiS_SetReg(SISSR, 0x14, 0x5a);
sisfb_post_xgi_delay(ivideo, 1);
sr14 = 0x0a;
if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
goto bail_out;
SiS_SetReg(SISSR, 0x13, 0x21);
SiS_SetReg(SISSR, 0x14, 0x4a);
}
sisfb_post_xgi_delay(ivideo, 1);
}
}
bail_out:
SiS_SetRegANDOR(SISSR, 0x14, 0xf0, sr14);
sisfb_post_xgi_delay(ivideo, 1);
j = (ivideo->chip == XGI_20) ? 5 : 9;
k = (ivideo->chip == XGI_20) ? 12 : 4;
status = -EIO;
for(i = 0; i < k; i++) {
reg = (ivideo->chip == XGI_20) ?
dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
SiS_SetRegANDOR(SISSR, 0x13, 0x80, reg);
sisfb_post_xgi_delay(ivideo, 50);
ranksize = (ivideo->chip == XGI_20) ?
dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
reg = SiS_GetReg(SISSR, 0x13);
if(reg & 0x80) ranksize <<= 1;
if(ivideo->chip == XGI_20) {
if(buswidth == 16) ranksize <<= 1;
else if(buswidth == 32) ranksize <<= 2;
} else {
if(buswidth == 64) ranksize <<= 1;
}
reg = 0;
l = channelab;
if(l == 3) l = 4;
if((ranksize * l) <= 256) {
while((ranksize >>= 1)) reg += 0x10;
}
if(!reg) continue;
SiS_SetRegANDOR(SISSR, 0x14, 0x0f, (reg & 0xf0));
sisfb_post_xgi_delay(ivideo, 1);
if (sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize)) {
status = 0;
break;
}
}
iounmap(ivideo->video_vbase);
return status;
}