cirrusfb: add mmio registers for Laguna chipsets

The Laguna chipsets use special registers which are available through the
mmio area.  The cirrusfb driver does not use memory mapped registers for
the PCI cards.

Add the memory mapped area for Laguna chipsets and add basic usage of the
special Laguna registers after SVGALIB code.

This gives readable console at 16bpp on the GD-5465 (Laguna AGP).  The
8bpp and 32bpp depths are still broken.

Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index 119e49e..378d60e 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -327,6 +327,7 @@
 /* info about board */
 struct cirrusfb_info {
 	u8 __iomem *regbase;
+	u8 __iomem *laguna_mmio;
 	enum cirrus_board btype;
 	unsigned char SFR;	/* Shadow of special function register */
 
@@ -699,6 +700,7 @@
 	int yres, vdispend, vsyncstart, vsyncend, vtotal;
 	long freq;
 	int nom, den, div;
+	unsigned int control, format, threshold;
 
 	dev_dbg(info->device, "Requested mode: %dx%dx%d\n",
 	       var->xres, var->yres, var->bits_per_pixel);
@@ -866,6 +868,23 @@
 			cirrusfb_set_mclk_as_source(info, divMCLK);
 		}
 	}
+	if (cinfo->btype == BT_LAGUNA) {
+		long pcifc = fb_readl(cinfo->laguna_mmio + 0x3fc);
+		unsigned char tile = fb_readb(cinfo->laguna_mmio + 0x407);
+		unsigned short tile_control;
+
+		tile_control = fb_readw(cinfo->laguna_mmio + 0x2c4);
+		fb_writew(tile_control & ~0x80, cinfo->laguna_mmio + 0x2c4);
+
+		fb_writel(pcifc | 0x10000000l, cinfo->laguna_mmio + 0x3fc);
+		fb_writeb(tile & 0x3f, cinfo->laguna_mmio + 0x407);
+		control = fb_readw(cinfo->laguna_mmio + 0x402);
+		threshold = fb_readw(cinfo->laguna_mmio + 0xea);
+		control &= ~0x6800;
+		format = 0;
+		threshold &= 0xffe0;
+		threshold &= 0x3fbf;
+	}
 	if (nom) {
 		tmp = den << 1;
 		if (div != 0)
@@ -1035,6 +1054,7 @@
 		case BT_LAGUNA:
 			vga_wseq(regbase, CL_SEQR7,
 				vga_rseq(regbase, CL_SEQR7) | 0x01);
+			threshold |= 0x10;
 			break;
 
 		default:
@@ -1146,6 +1166,9 @@
 		case BT_LAGUNA:
 			vga_wseq(regbase, CL_SEQR7,
 				vga_rseq(regbase, CL_SEQR7) & ~0x01);
+			control |= 0x2000;
+			format |= 0x1400;
+			threshold |= 0x10;
 			break;
 
 		default:
@@ -1220,6 +1243,9 @@
 		case BT_LAGUNA:
 			vga_wseq(regbase, CL_SEQR7,
 				vga_rseq(regbase, CL_SEQR7) & ~0x01);
+			control |= 0x6000;
+			format |= 0x3400;
+			threshold |= 0x20;
 			break;
 
 		default:
@@ -1327,6 +1353,12 @@
 	/* graphics cursor attributes: nothing special */
 	vga_wseq(regbase, CL_SEQR12, 0x0);
 
+	if (cinfo->btype == BT_LAGUNA) {
+		/* no tiles */
+		fb_writew(control | 0x1000, cinfo->laguna_mmio + 0x402);
+		fb_writew(format, cinfo->laguna_mmio + 0xc0);
+		fb_writew(threshold, cinfo->laguna_mmio + 0xea);
+	}
 	/* finally, turn on everything - turn off "FullBandwidth" bit */
 	/* also, set "DotClock%2" bit where requested */
 	tmp = 0x01;
@@ -2000,7 +2032,10 @@
 static void cirrusfb_pci_unmap(struct fb_info *info)
 {
 	struct pci_dev *pdev = to_pci_dev(info->device);
+	struct cirrusfb_info *cinfo = info->par;
 
+	if (cinfo->laguna_mmio == NULL)
+		iounmap(cinfo->laguna_mmio);
 	iounmap(info->screen_base);
 #if 0 /* if system didn't claim this region, we would... */
 	release_mem_region(0xA0000, 65535);
@@ -2180,6 +2215,7 @@
 		get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start);
 		/* FIXME: this forces VGA.  alternatives? */
 		cinfo->regbase = NULL;
+		cinfo->laguna_mmio = ioremap(info->fix.mmio_start, 0x1000);
 	}
 
 	dev_dbg(info->device, "Board address: 0x%lx, register address: 0x%lx\n",
@@ -2234,6 +2270,8 @@
 #endif
 	pci_release_regions(pdev);
 err_release_fb:
+	if (cinfo->laguna_mmio == NULL)
+		iounmap(cinfo->laguna_mmio);
 	framebuffer_release(info);
 err_disable:
 err_out: