static int sisfb_post_xgi_ramsize()

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;
}