+ for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
+
+ rom_base = ioremap(temp, 65536);
+ if(!rom_base)
+ continue;
+
+ if(!sisfb_check_rom(rom_base, ivideo)) {
+ iounmap(rom_base);
+ continue;
+ }
+
+ if((myrombase = vmalloc(65536)))
+ memcpy_fromio(myrombase, rom_base, 65536);
+
+ iounmap(rom_base);
+ break;
+
+ }
+
+#else
+
+ pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
+ pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
+ (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
+
+ rom_base = ioremap(ivideo->video_base, 65536);
+ if(rom_base) {
+ if(sisfb_check_rom(rom_base, ivideo)) {
+ if((myrombase = vmalloc(65536)))
+ memcpy_fromio(myrombase, rom_base, 65536);
+ }
+ iounmap(rom_base);
+ }
+
+ pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
+
+#endif
+
+ return myrombase;
+}
+
+static void __devinit
+sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
+ unsigned int min)
+{
+ ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
+
+ if(!ivideo->video_vbase) {
+ printk(KERN_ERR
+ "sisfb: Unable to map maximum video RAM for size detection\n");
+ (*mapsize) >>= 1;
+ while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
+ (*mapsize) >>= 1;
+ if((*mapsize) < (min << 20))
+ break;
+ }
+ if(ivideo->video_vbase) {
+ printk(KERN_ERR
+ "sisfb: Video RAM size detection limited to %dMB\n",
+ (int)((*mapsize) >> 20));
+ }
+ }
+}
+
+#ifdef CONFIG_FB_SIS_300
+static int __devinit
+sisfb_post_300_buswidth(struct sis_video_info *ivideo)
+{
+ SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
+ unsigned short temp;
+ unsigned char reg;
+ int i, j;
+
+ andSISIDXREG(SISSR, 0x15, 0xFB);
+ orSISIDXREG(SISSR, 0x15, 0x04);
+ outSISIDXREG(SISSR, 0x13, 0x00);
+ outSISIDXREG(SISSR, 0x14, 0xBF);
+
+ for(i = 0; i < 2; i++) {
+ temp = 0x1234;
+ for(j = 0; j < 4; j++) {
+ writew(temp, FBAddress);
+ if(readw(FBAddress) == temp)
+ break;
+ orSISIDXREG(SISSR, 0x3c, 0x01);
+ inSISIDXREG(SISSR, 0x05, reg);
+ inSISIDXREG(SISSR, 0x05, reg);
+ andSISIDXREG(SISSR, 0x3c, 0xfe);
+ inSISIDXREG(SISSR, 0x05, reg);
+ inSISIDXREG(SISSR, 0x05, reg);
+ temp++;
+ }
+ }
+
+ writel(0x01234567L, FBAddress);
+ writel(0x456789ABL, (FBAddress + 4));
+ writel(0x89ABCDEFL, (FBAddress + 8));
+ writel(0xCDEF0123L, (FBAddress + 12));
+
+ inSISIDXREG(SISSR, 0x3b, reg);
+ if(reg & 0x01) {
+ if(readl((FBAddress + 12)) == 0xCDEF0123L)
+ return 4; /* Channel A 128bit */
+ }
+
+ if(readl((FBAddress + 4)) == 0x456789ABL)
+ return 2; /* Channel B 64bit */
+
+ return 1; /* 32bit */
+}
+
+static int __devinit
+sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
+ int PseudoRankCapacity, int PseudoAdrPinCount,
+ unsigned int mapsize)
+{
+ SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
+ unsigned short sr14;
+ unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
+ unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
+ static const unsigned short SiS_DRAMType[17][5] = {
+ {0x0C,0x0A,0x02,0x40,0x39},
+ {0x0D,0x0A,0x01,0x40,0x48},
+ {0x0C,0x09,0x02,0x20,0x35},
+ {0x0D,0x09,0x01,0x20,0x44},
+ {0x0C,0x08,0x02,0x10,0x31},
+ {0x0D,0x08,0x01,0x10,0x40},
+ {0x0C,0x0A,0x01,0x20,0x34},
+ {0x0C,0x09,0x01,0x08,0x32},
+ {0x0B,0x08,0x02,0x08,0x21},
+ {0x0C,0x08,0x01,0x08,0x30},
+ {0x0A,0x08,0x02,0x04,0x11},
+ {0x0B,0x0A,0x01,0x10,0x28},
+ {0x09,0x08,0x02,0x02,0x01},
+ {0x0B,0x09,0x01,0x08,0x24},
+ {0x0B,0x08,0x01,0x04,0x20},
+ {0x0A,0x08,0x01,0x02,0x10},
+ {0x09,0x08,0x01,0x01,0x00}
+ };
+
+ for(k = 0; k <= 16; k++) {
+
+ RankCapacity = buswidth * SiS_DRAMType[k][3];
+
+ if(RankCapacity != PseudoRankCapacity)
+ continue;
+
+ if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
+ continue;
+
+ BankNumHigh = RankCapacity * 16 * iteration - 1;
+ if(iteration == 3) { /* Rank No */
+ BankNumMid = RankCapacity * 16 - 1;
+ } else {
+ BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
+ }
+
+ PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
+ PhysicalAdrHigh = BankNumHigh;
+ PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
+ PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
+
+ andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
+ orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
+ sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
+ if(buswidth == 4) sr14 |= 0x80;
+ else if(buswidth == 2) sr14 |= 0x40;
+ outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
+ outSISIDXREG(SISSR, 0x14, sr14);
+
+ BankNumHigh <<= 16;
+ BankNumMid <<= 16;
+
+ if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
+ (BankNumMid + PhysicalAdrHigh >= mapsize) ||
+ (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
+ (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
+ continue;
+
+ /* Write data */
+ writew(((unsigned short)PhysicalAdrHigh),
+ (FBAddr + BankNumHigh + PhysicalAdrHigh));
+ writew(((unsigned short)BankNumMid),
+ (FBAddr + BankNumMid + PhysicalAdrHigh));
+ writew(((unsigned short)PhysicalAdrHalfPage),
+ (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
+ writew(((unsigned short)PhysicalAdrOtherPage),
+ (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
+
+ /* Read data */
+ if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void __devinit
+sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
+{
+ struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+ int i, j, buswidth;
+ int PseudoRankCapacity, PseudoAdrPinCount;
+
+ buswidth = sisfb_post_300_buswidth(ivideo);
+
+ for(i = 6; i >= 0; i--) {
+ PseudoRankCapacity = 1 << i;
+ for(j = 4; j >= 1; j--) {
+ PseudoAdrPinCount = 15 - j;
+ if((PseudoRankCapacity * j) <= 64) {
+ if(sisfb_post_300_rwtest(ivideo,
+ j,
+ buswidth,
+ PseudoRankCapacity,
+ PseudoAdrPinCount,
+ mapsize))
+ return;
+ }
+ }
+ }
+}
+
+static void __devinit
+sisfb_post_sis300(struct pci_dev *pdev)
+{
+ struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+ unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
+ u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
+ u16 index, rindex, memtype = 0;
+ unsigned int mapsize;
+
+ if(!ivideo->SiS_Pr.UseROM)
+ bios = NULL;
+
+ outSISIDXREG(SISSR, 0x05, 0x86);
+
+ if(bios) {
+ if(bios[0x52] & 0x80) {
+ memtype = bios[0x52];
+ } else {
+ inSISIDXREG(SISSR, 0x3a, memtype);
+ }
+ memtype &= 0x07;
+ }
+
+ v3 = 0x80; v6 = 0x80;
+ if(ivideo->revision_id <= 0x13) {
+ v1 = 0x44; v2 = 0x42;
+ v4 = 0x44; v5 = 0x42;
+ } else {
+ v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
+ v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
+ if(bios) {
+ index = memtype * 5;
+ rindex = index + 0x54;
+ v1 = bios[rindex++];
+ v2 = bios[rindex++];
+ v3 = bios[rindex++];
+ rindex = index + 0x7c;
+ v4 = bios[rindex++];
+ v5 = bios[rindex++];
+ v6 = bios[rindex++];
+ }
+ }
+ outSISIDXREG(SISSR, 0x28, v1);
+ outSISIDXREG(SISSR, 0x29, v2);
+ outSISIDXREG(SISSR, 0x2a, v3);
+ outSISIDXREG(SISSR, 0x2e, v4);
+ outSISIDXREG(SISSR, 0x2f, v5);
+ outSISIDXREG(SISSR, 0x30, v6);
+
+ v1 = 0x10;
+ if(bios)
+ v1 = bios[0xa4];
+ outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
+
+ outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
+
+ v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
+ v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
+ if(bios) {
+ memtype += 0xa5;
+ v1 = bios[memtype];
+ v2 = bios[memtype + 8];
+ v3 = bios[memtype + 16];
+ v4 = bios[memtype + 24];
+ v5 = bios[memtype + 32];
+ v6 = bios[memtype + 40];
+ v7 = bios[memtype + 48];
+ v8 = bios[memtype + 56];
+ }
+ if(ivideo->revision_id >= 0x80)
+ v3 &= 0xfd;
+ outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
+ outSISIDXREG(SISSR, 0x16, v2);
+ outSISIDXREG(SISSR, 0x17, v3);
+ outSISIDXREG(SISSR, 0x18, v4);
+ outSISIDXREG(SISSR, 0x19, v5);
+ outSISIDXREG(SISSR, 0x1a, v6);
+ outSISIDXREG(SISSR, 0x1b, v7);
+ outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
+ andSISIDXREG(SISSR, 0x15 ,0xfb);
+ orSISIDXREG(SISSR, 0x15, 0x04);
+ if(bios) {
+ if(bios[0x53] & 0x02) {
+ orSISIDXREG(SISSR, 0x19, 0x20);
+ }
+ }
+ v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
+ if(ivideo->revision_id >= 0x80)
+ v1 |= 0x01;
+ outSISIDXREG(SISSR, 0x1f, v1);
+ outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
+ v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
+ if(bios) {
+ v1 = bios[0xe8];
+ v2 = bios[0xe9];
+ v3 = bios[0xea];
+ }
+ outSISIDXREG(SISSR, 0x23, v1);
+ outSISIDXREG(SISSR, 0x24, v2);
+ outSISIDXREG(SISSR, 0x25, v3);
+ outSISIDXREG(SISSR, 0x21, 0x84);
+ outSISIDXREG(SISSR, 0x22, 0x00);
+ outSISIDXREG(SISCR, 0x37, 0x00);
+ orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
+ outSISIDXREG(SISPART1, 0x00, 0x00);
+ v1 = 0x40; v2 = 0x11;
+ if(bios) {
+ v1 = bios[0xec];
+ v2 = bios[0xeb];
+ }
+ outSISIDXREG(SISPART1, 0x02, v1);
+
+ if(ivideo->revision_id >= 0x80)
+ v2 &= ~0x01;
+
+ inSISIDXREG(SISPART4, 0x00, reg);
+ if((reg == 1) || (reg == 2)) {
+ outSISIDXREG(SISCR, 0x37, 0x02);
+ outSISIDXREG(SISPART2, 0x00, 0x1c);
+ v4 = 0x00; v5 = 0x00; v6 = 0x10;
+ if(ivideo->SiS_Pr.UseROM) {
+ v4 = bios[0xf5];
+ v5 = bios[0xf6];
+ v6 = bios[0xf7];
+ }
+ outSISIDXREG(SISPART4, 0x0d, v4);
+ outSISIDXREG(SISPART4, 0x0e, v5);
+ outSISIDXREG(SISPART4, 0x10, v6);
+ outSISIDXREG(SISPART4, 0x0f, 0x3f);
+ inSISIDXREG(SISPART4, 0x01, reg);
+ if(reg >= 0xb0) {
+ inSISIDXREG(SISPART4, 0x23, reg);
+ reg &= 0x20;
+ reg <<= 1;
+ outSISIDXREG(SISPART4, 0x23, reg);
+ }
+ } else {
+ v2 &= ~0x10;
+ }
+ outSISIDXREG(SISSR, 0x32, v2);
+
+ andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
+
+ inSISIDXREG(SISSR, 0x16, reg);
+ reg &= 0xc3;
+ outSISIDXREG(SISCR, 0x35, reg);
+ outSISIDXREG(SISCR, 0x83, 0x00);
+#if !defined(__i386__) && !defined(__x86_64__)
+ if(sisfb_videoram) {
+ outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
+ reg = ((sisfb_videoram >> 10) - 1) | 0x40;
+ outSISIDXREG(SISSR, 0x14, reg);
+ } else {
+#endif
+ /* Need to map max FB size for finding out about RAM size */
+ mapsize = 64 << 20;
+ sisfb_post_map_vram(ivideo, &mapsize, 4);
+
+ if(ivideo->video_vbase) {
+ sisfb_post_300_ramsize(pdev, mapsize);
+ iounmap(ivideo->video_vbase);
+ } else {
+ printk(KERN_DEBUG
+ "sisfb: Failed to map memory for size detection, assuming 8MB\n");
+ outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
+ outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
+ }
+#if !defined(__i386__) && !defined(__x86_64__)
+ }
+#endif
+ if(bios) {
+ v1 = bios[0xe6];
+ v2 = bios[0xe7];
+ } else {
+ inSISIDXREG(SISSR, 0x3a, reg);
+ if((reg & 0x30) == 0x30) {
+ v1 = 0x04; /* PCI */
+ v2 = 0x92;
+ } else {
+ v1 = 0x14; /* AGP */
+ v2 = 0xb2;
+ }
+ }
+ outSISIDXREG(SISSR, 0x21, v1);
+ outSISIDXREG(SISSR, 0x22, v2);
+
+ /* Sense CRT1 */
+ sisfb_sense_crt1(ivideo);
+
+ /* Set default mode, don't clear screen */
+ ivideo->SiS_Pr.SiS_UseOEM = FALSE;
+ SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
+ SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
+ ivideo->curFSTN = ivideo->curDSTN = 0;
+ ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
+ SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
+
+ outSISIDXREG(SISSR, 0x05, 0x86);
+
+ /* Display off */
+ orSISIDXREG(SISSR, 0x01, 0x20);
+
+ /* Save mode number in CR34 */
+ outSISIDXREG(SISCR, 0x34, 0x2e);
+
+ /* Let everyone know what the current mode is */
+ ivideo->modeprechange = 0x2e;
+}
+#endif
+
+#ifdef CONFIG_FB_SIS_315
+#if 0
+static void __devinit
+sisfb_post_sis315330(struct pci_dev *pdev)
+{
+ /* TODO */
+}
+#endif
+
+static void __devinit
+sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
+{
+ unsigned int i;
+ u8 reg;
+
+ for(i = 0; i <= (delay * 10 * 36); i++) {
+ inSISIDXREG(SISSR, 0x05, reg);
+ reg++;
+ }
+}
+
+static int __devinit
+sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
+ unsigned short pcivendor)
+{
+ struct pci_dev *pdev = NULL;
+ unsigned short temp;
+ int ret = 0;
+
+ while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
+ temp = pdev->vendor;
+ SIS_PCI_PUT_DEVICE(pdev);
+ if(temp == pcivendor) {
+ ret = 1;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int __devinit
+sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
+ unsigned int enda, unsigned int mapsize)
+{
+ unsigned int pos;
+ int i;
+
+ writel(0, ivideo->video_vbase);
+
+ for(i = starta; i <= enda; i++) {
+ pos = 1 << i;
+ if(pos < mapsize)
+ writel(pos, ivideo->video_vbase + pos);
+ }
+
+ sisfb_post_xgi_delay(ivideo, 150);
+
+ if(readl(ivideo->video_vbase) != 0)
+ return 0;
+
+ for(i = starta; i <= enda; i++) {
+ pos = 1 << i;
+ if(pos < mapsize) {
+ if(readl(ivideo->video_vbase + pos) != pos)
+ return 0;
+ } else
+ return 0;
+ }
+
+ return 1;
+}
+
+static void __devinit
+sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
+{
+ unsigned int buswidth, ranksize, channelab, mapsize;
+ int i, j, k, l;
+ 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.
+ */
+ orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
+
+ /* Need to map max FB size for finding out about RAM size */
+ mapsize = 256 << 20;
+ sisfb_post_map_vram(ivideo, &mapsize, 32);
+
+ if(!ivideo->video_vbase) {
+ printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
+ outSISIDXREG(SISSR, 0x13, 0x35);
+ outSISIDXREG(SISSR, 0x14, 0x41);
+ /* TODO */
+ return;
+ }
+
+ /* Non-interleaving */
+ outSISIDXREG(SISSR, 0x15, 0x00);
+ /* No tiling */
+ outSISIDXREG(SISSR, 0x1c, 0x00);
+
+ if(ivideo->chip == XGI_20) {
+
+ channelab = 1;
+ inSISIDXREG(SISCR, 0x97, reg);
+ if(!(reg & 0x01)) { /* Single 32/16 */
+ buswidth = 32;
+ outSISIDXREG(SISSR, 0x13, 0xb1);
+ outSISIDXREG(SISSR, 0x14, 0x52);
+ sisfb_post_xgi_delay(ivideo, 1);
+ sr14 = 0x02;
+ if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
+ goto bail_out;
+
+ outSISIDXREG(SISSR, 0x13, 0x31);
+ outSISIDXREG(SISSR, 0x14, 0x42);
+ sisfb_post_xgi_delay(ivideo, 1);
+ if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
+ goto bail_out;
+
+ buswidth = 16;
+ outSISIDXREG(SISSR, 0x13, 0xb1);
+ outSISIDXREG(SISSR, 0x14, 0x41);
+ sisfb_post_xgi_delay(ivideo, 1);
+ sr14 = 0x01;
+ if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
+ goto bail_out;
+ else
+ outSISIDXREG(SISSR, 0x13, 0x31);
+ } else { /* Dual 16/8 */
+ buswidth = 16;
+ outSISIDXREG(SISSR, 0x13, 0xb1);
+ outSISIDXREG(SISSR, 0x14, 0x41);
+ sisfb_post_xgi_delay(ivideo, 1);
+ sr14 = 0x01;
+ if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
+ goto bail_out;
+
+ outSISIDXREG(SISSR, 0x13, 0x31);
+ outSISIDXREG(SISSR, 0x14, 0x31);
+ sisfb_post_xgi_delay(ivideo, 1);
+ if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
+ goto bail_out;
+
+ buswidth = 8;
+ outSISIDXREG(SISSR, 0x13, 0xb1);
+ outSISIDXREG(SISSR, 0x14, 0x30);
+ sisfb_post_xgi_delay(ivideo, 1);
+ sr14 = 0x00;
+ if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
+ goto bail_out;
+ else
+ outSISIDXREG(SISSR, 0x13, 0x31);
+ }
+
+ } else { /* XGI_40 */
+
+ inSISIDXREG(SISCR, 0x97, reg);
+ if(!(reg & 0x10)) {
+ inSISIDXREG(SISSR, 0x39, reg);
+ reg >>= 1;
+ }
+
+ if(reg & 0x01) { /* DDRII */
+ buswidth = 32;
+ if(ivideo->revision_id == 2) {
+ channelab = 2;
+ outSISIDXREG(SISSR, 0x13, 0xa1);
+ outSISIDXREG(SISSR, 0x14, 0x44);
+ sr14 = 0x04;
+ sisfb_post_xgi_delay(ivideo, 1);
+ if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
+ goto bail_out;
+
+ outSISIDXREG(SISSR, 0x13, 0x21);
+ outSISIDXREG(SISSR, 0x14, 0x34);
+ if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
+ goto bail_out;
+
+ channelab = 1;
+ outSISIDXREG(SISSR, 0x13, 0xa1);
+ outSISIDXREG(SISSR, 0x14, 0x40);
+ sr14 = 0x00;
+ if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
+ goto bail_out;
+
+ outSISIDXREG(SISSR, 0x13, 0x21);
+ outSISIDXREG(SISSR, 0x14, 0x30);
+ } else {
+ channelab = 3;
+ outSISIDXREG(SISSR, 0x13, 0xa1);
+ outSISIDXREG(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;
+ outSISIDXREG(SISSR, 0x14, 0x48);
+ sisfb_post_xgi_delay(ivideo, 1);
+ sr14 = 0x08;
+ if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
+ goto bail_out;
+
+ outSISIDXREG(SISSR, 0x13, 0x21);
+ outSISIDXREG(SISSR, 0x14, 0x3c);
+ sr14 = 0x0c;
+
+ if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
+ channelab = 3;
+ } else {
+ channelab = 2;
+ outSISIDXREG(SISSR, 0x14, 0x38);
+ sr14 = 0x08;
+ }
+ }
+ sisfb_post_xgi_delay(ivideo, 1);
+
+ } else { /* DDR */
+
+ buswidth = 64;
+ if(ivideo->revision_id == 2) {
+ channelab = 1;
+ outSISIDXREG(SISSR, 0x13, 0xa1);
+ outSISIDXREG(SISSR, 0x14, 0x52);
+ sisfb_post_xgi_delay(ivideo, 1);
+ sr14 = 0x02;
+ if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
+ goto bail_out;
+
+ outSISIDXREG(SISSR, 0x13, 0x21);
+ outSISIDXREG(SISSR, 0x14, 0x42);
+ } else {
+ channelab = 2;
+ outSISIDXREG(SISSR, 0x13, 0xa1);
+ outSISIDXREG(SISSR, 0x14, 0x5a);
+ sisfb_post_xgi_delay(ivideo, 1);
+ sr14 = 0x0a;
+ if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
+ goto bail_out;
+
+ outSISIDXREG(SISSR, 0x13, 0x21);
+ outSISIDXREG(SISSR, 0x14, 0x4a);
+ }
+ sisfb_post_xgi_delay(ivideo, 1);
+
+ }
+ }
+
+bail_out:
+ setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
+ sisfb_post_xgi_delay(ivideo, 1);
+
+ j = (ivideo->chip == XGI_20) ? 5 : 9;
+ k = (ivideo->chip == XGI_20) ? 12 : 4;
+
+ for(i = 0; i < k; i++) {
+
+ reg = (ivideo->chip == XGI_20) ?
+ dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
+ setSISIDXREG(SISSR, 0x13, 0x80, reg);
+ sisfb_post_xgi_delay(ivideo, 50);
+
+ ranksize = (ivideo->chip == XGI_20) ?
+ dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
+
+ inSISIDXREG(SISSR, 0x13, reg);
+ 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;
+
+ setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
+ sisfb_post_xgi_delay(ivideo, 1);
+
+ if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
+ break;
+ }
+
+ iounmap(ivideo->video_vbase);
+}
+
+static void __devinit
+sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
+{
+ u8 v1, v2, v3;
+ int index;
+ static const u8 cs90[8 * 3] = {
+ 0x16, 0x01, 0x01,
+ 0x3e, 0x03, 0x01,
+ 0x7c, 0x08, 0x01,
+ 0x79, 0x06, 0x01,
+ 0x29, 0x01, 0x81,
+ 0x5c, 0x23, 0x01,
+ 0x5c, 0x23, 0x01,
+ 0x5c, 0x23, 0x01
+ };
+ static const u8 csb8[8 * 3] = {
+ 0x5c, 0x23, 0x01,
+ 0x29, 0x01, 0x01,
+ 0x7c, 0x08, 0x01,
+ 0x79, 0x06, 0x01,
+ 0x29, 0x01, 0x81,
+ 0x5c, 0x23, 0x01,
+ 0x5c, 0x23, 0x01,
+ 0x5c, 0x23, 0x01
+ };
+
+ regb = 0; /* ! */
+
+ index = regb * 3;
+ v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
+ if(ivideo->haveXGIROM) {
+ v1 = ivideo->bios_abase[0x90 + index];
+ v2 = ivideo->bios_abase[0x90 + index + 1];
+ v3 = ivideo->bios_abase[0x90 + index + 2];
+ }
+ outSISIDXREG(SISSR, 0x28, v1);
+ outSISIDXREG(SISSR, 0x29, v2);
+ outSISIDXREG(SISSR, 0x2a, v3);
+ sisfb_post_xgi_delay(ivideo, 0x43);
+ sisfb_post_xgi_delay(ivideo, 0x43);
+ sisfb_post_xgi_delay(ivideo, 0x43);
+ index = regb * 3;
+ v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
+ if(ivideo->haveXGIROM) {
+ v1 = ivideo->bios_abase[0xb8 + index];
+ v2 = ivideo->bios_abase[0xb8 + index + 1];
+ v3 = ivideo->bios_abase[0xb8 + index + 2];
+ }
+ outSISIDXREG(SISSR, 0x2e, v1);
+ outSISIDXREG(SISSR, 0x2f, v2);
+ outSISIDXREG(SISSR, 0x30, v3);
+ sisfb_post_xgi_delay(ivideo, 0x43);
+ sisfb_post_xgi_delay(ivideo, 0x43);
+ sisfb_post_xgi_delay(ivideo, 0x43);
+}
+
+static int __devinit
+sisfb_post_xgi(struct pci_dev *pdev)
+{
+ struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+ unsigned char *bios = ivideo->bios_abase;
+ struct pci_dev *mypdev = NULL;
+ const u8 *ptr, *ptr2;
+ u8 v1, v2, v3, v4, v5, reg, ramtype;
+ u32 rega, regb, regd;
+ int i, j, k, index;
+ static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
+ static const u8 cs76[2] = { 0xa3, 0xfb };
+ static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
+ static const u8 cs158[8] = {
+ 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const u8 cs160[8] = {
+ 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const u8 cs168[8] = {
+ 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const u8 cs128[3 * 8] = {
+ 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const u8 cs148[2 * 8] = {
+ 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const u8 cs31a[8 * 4] = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const u8 cs33a[8 * 4] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const u8 cs45a[8 * 2] = {
+ 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const u8 cs170[7 * 8] = {
+ 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const u8 cs1a8[3 * 8] = {
+ 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const u8 cs100[2 * 8] = {
+ 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
+ };