
From: "Antonino A. Daplas" <adaplas@hotpop.com>

Although the rivafb advertises its capability as DirectColor, the hardware
is actually set in Truecolor (CLUT cannot be altered).  This mismatch
occasionally produces wrong colors, such as wrong logo colors at 32bpp and
gamma utilities (such as xgamma) does not work at all.

Changes:

1. Fixes the above problems by setting the hardware to accept changing
   of the CLUT.

2. Fixes color problems for NV_ARCH_03 (Riva128)

3. Build a private modelist from the EDID (for use by fbcon)

4. Mark several functions/data as __devinit/__initdata

5. Remove unused fields from struct riva_par 

Signed-off-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/drivers/video/riva/fbdev.c      |  194 ++++++++++++++------------------
 25-akpm/drivers/video/riva/riva_hw.c    |    7 -
 25-akpm/drivers/video/riva/rivafb-i2c.c |    5 
 25-akpm/drivers/video/riva/rivafb.h     |    5 
 4 files changed, 95 insertions(+), 116 deletions(-)

diff -puN drivers/video/riva/fbdev.c~rivafb-directcolor-mode-and-miscellaneous-fixes drivers/video/riva/fbdev.c
--- 25/drivers/video/riva/fbdev.c~rivafb-directcolor-mode-and-miscellaneous-fixes	2004-08-21 13:47:37.750876528 -0700
+++ 25-akpm/drivers/video/riva/fbdev.c	2004-08-21 13:47:37.773873032 -0700
@@ -203,7 +203,6 @@ MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl)
  * ------------------------------------------------------------------------- */
 
 /* command line data, set in rivafb_setup() */
-static u32 pseudo_palette[17];
 static int flatpanel __initdata = -1; /* Autodetect later */
 static int forceCRTC __initdata = -1;
 #ifdef CONFIG_MTRR
@@ -213,13 +212,13 @@ static int nomtrr __initdata = 0;
 static char *mode_option __initdata = NULL;
 static int  strictmode       = 0;
 
-static struct fb_fix_screeninfo rivafb_fix = {
+static struct fb_fix_screeninfo __initdata rivafb_fix = {
 	.type		= FB_TYPE_PACKED_PIXELS,
 	.xpanstep	= 1,
 	.ypanstep	= 1,
 };
 
-static struct fb_var_screeninfo rivafb_default_var = {
+static struct fb_var_screeninfo __initdata rivafb_default_var = {
 	.xres		= 640,
 	.yres		= 480,
 	.xres_virtual	= 640,
@@ -515,7 +514,7 @@ static void riva_rclut(RIVA_HW_INST *chi
 		       unsigned char *green, unsigned char *blue)
 {
 	
-	VGA_WR08(chip->PDIO, 0x3c8, regnum);
+	VGA_WR08(chip->PDIO, 0x3c7, regnum);
 	*red = VGA_RD08(chip->PDIO, 0x3c9);
 	*green = VGA_RD08(chip->PDIO, 0x3c9);
 	*blue = VGA_RD08(chip->PDIO, 0x3c9);
@@ -1007,6 +1006,7 @@ static int rivafb_open(struct fb_info *i
 			par->state.flags |= VGA_SAVE_CMAP;
 		save_vga(&par->state);
 #endif
+		riva_common_setup(par);
 		RivaGetConfig(&par->riva, par->Chipset);
 		/* vgaHWunlock() + riva unlock (0x7F) */
 		CRTCout(par, 0x11, 0xFF);
@@ -1043,7 +1043,8 @@ static int rivafb_release(struct fb_info
 
 static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
-	struct fb_monspecs *specs = &info->monspecs;
+	struct fb_videomode *mode;
+	struct riva_par *par = (struct riva_par *) info->par;
 	int nom, den;		/* translating from pixels->bytes */
 	int mode_valid = 0;
 	
@@ -1060,6 +1061,9 @@ static int rivafb_check_var(struct fb_va
 		/* fall through */
 	case 16:
 		var->bits_per_pixel = 16;
+		/* The Riva128 supports RGB555 only */
+		if (par->riva.Architecture == NV_ARCH_03)
+			var->green.length = 5;
 		if (var->green.length == 5) {
 			/* 0rrrrrgg gggbbbbb */
 			var->red.offset = 10;
@@ -1102,62 +1106,21 @@ static int rivafb_check_var(struct fb_va
 			mode_valid = 1;
 	}
 
-	/* find best mode from modedb */
-	if (!mode_valid && specs->modedb_len) {
-		int i, best, best_refresh, best_x, best_y, diff_x, diff_y;
-
-		best_refresh = best = best_x = best_y = 0;
-		diff_x = diff_y = -1;
-
-		for (i = 0; i < specs->modedb_len; i++) {
-			if (var->xres <= specs->modedb[i].xres &&
-			    !(specs->modedb[i].flag & FB_MODE_IS_CALCULATED) &&
-			    specs->modedb[i].xres - var->xres < diff_x) {
-				best_x = specs->modedb[i].xres;
-				diff_x = best_x - var->xres;
-			}
-			if (!diff_x) break;
-		}
-
-		if (diff_x != -1) {
-			for (i = 0; i < specs->modedb_len; i++) {
-				if (best_x == specs->modedb[i].xres &&
-				    var->yres <= specs->modedb[i].yres &&
-				    !(specs->modedb[i].flag &
-				      FB_MODE_IS_CALCULATED) &&
-				    specs->modedb[i].yres-var->yres < diff_y) {
-					best_y = specs->modedb[i].yres;
-					diff_y = best_y - var->yres;
-				}
-				if (!diff_y) break;
-			}
-		}
-
-		if (diff_y != -1) {
-			for (i = 0; i < specs->modedb_len; i++) {
-				if (best_x == specs->modedb[i].xres &&
-				    best_y == specs->modedb[i].yres &&
-				    !(specs->modedb[i].flag &
-				      FB_MODE_IS_CALCULATED) &&
-				    specs->modedb[i].refresh > best_refresh) {
-					best_refresh=specs->modedb[i].refresh;
-					best = i;
-				}
-			}
-		}
-
-		if (best_refresh) {
-			riva_update_var(var, &specs->modedb[best]);
-			mode_valid = 1;
-		}
-	}
-
 	/* calculate modeline if supported by monitor */
 	if (!mode_valid && info->monspecs.gtf) {
 		if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
 			mode_valid = 1;
 	}
-	if (!mode_valid && info->monspecs.modedb_len)
+
+	if (!mode_valid) {
+		mode = fb_find_best_mode(var, &info->monspecs.modelist);
+		if (mode) {
+			riva_update_var(var, mode);
+			mode_valid = 1;
+		}
+	}
+
+	if (!mode_valid && !list_empty(&info->monspecs.modelist))
 		return -EINVAL;
 
 	if (var->xres_virtual < var->xres)
@@ -1192,12 +1155,6 @@ static int rivafb_set_par(struct fb_info
 	struct riva_par *par = (struct riva_par *) info->par;
 
 	NVTRACE_ENTER();
-	riva_common_setup(par);
-	RivaGetConfig(&par->riva, par->Chipset);
-	/* vgaHWunlock() + riva unlock (0x7F) */
-	CRTCout(par, 0x11, 0xFF);
-	par->riva.LockUnlock(&par->riva, 0);
-
 	riva_load_video_mode(info);
 	riva_setup_accel(info);
 	
@@ -1205,6 +1162,7 @@ static int rivafb_set_par(struct fb_info
 	info->fix.line_length = (info->var.xres_virtual * (info->var.bits_per_pixel >> 3));
 	info->fix.visual = (info->var.bits_per_pixel == 8) ?
 				FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
+
 	NVTRACE_LEAVE();
 	return 0;
 }
@@ -1325,7 +1283,7 @@ static int rivafb_setcolreg(unsigned reg
 	int i;
 
 	if (regno >= riva_get_cmap_len(&info->var))
-		return -EINVAL;
+			return -EINVAL;
 
 	if (info->var.grayscale) {
 		/* gray = 0.30*R + 0.59*G + 0.11*B */
@@ -1333,6 +1291,31 @@ static int rivafb_setcolreg(unsigned reg
 		    (red * 77 + green * 151 + blue * 28) >> 8;
 	}
 
+	if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+		((u32 *) info->pseudo_palette)[regno] =
+			(regno << info->var.red.offset) |
+			(regno << info->var.green.offset) |
+			(regno << info->var.blue.offset);
+		/*
+		 * The Riva128 2D engine requires color information in
+		 * TrueColor format even if framebuffer is in DirectColor
+		 */
+		if (par->riva.Architecture == NV_ARCH_03) {
+			switch (info->var.bits_per_pixel) {
+			case 16:
+				par->palette[regno] = ((red & 0xf800) >> 1) |
+					((green & 0xf800) >> 6) |
+					((blue & 0xf800) >> 11);
+				break;
+			case 32:
+				par->palette[regno] = ((red & 0xff00) << 8) |
+					((green & 0xff00)) |
+					((blue & 0xff00) >> 8);
+				break;
+			}
+		}
+	}
+
 	switch (info->var.bits_per_pixel) {
 	case 8:
 		/* "transparent" stuff is completely ignored. */
@@ -1340,45 +1323,27 @@ static int rivafb_setcolreg(unsigned reg
 		break;
 	case 16:
 		if (info->var.green.length == 5) {
-			if (regno < 16) {
-				/* 0rrrrrgg gggbbbbb */
-				((u32 *)info->pseudo_palette)[regno] =
-					((red & 0xf800) >> 1) |
-					((green & 0xf800) >> 6) |
-					((blue & 0xf800) >> 11);
-			}
-			for (i = 0; i < 8; i++) 
+			for (i = 0; i < 8; i++) {
 				riva_wclut(chip, regno*8+i, red >> 8,
 					   green >> 8, blue >> 8);
+			}
 		} else {
 			u8 r, g, b;
 
-			if (regno < 16) {
-				/* rrrrrggg gggbbbbb */
-				((u32 *)info->pseudo_palette)[regno] =
-					((red & 0xf800) >> 0) |
-					((green & 0xf800) >> 5) |
-					((blue & 0xf800) >> 11);
-			}
 			if (regno < 32) {
 				for (i = 0; i < 8; i++) {
-					riva_wclut(chip, regno*8+i, red >> 8, 
-						   green >> 8, blue >> 8);
+					riva_wclut(chip, regno*8+i,
+						   red >> 8, green >> 8,
+						   blue >> 8);
 				}
 			}
-			for (i = 0; i < 4; i++) {
-				riva_rclut(chip, regno*2+i, &r, &g, &b);
-				riva_wclut(chip, regno*4+i, r, green >> 8, b);
-			}
+			riva_rclut(chip, regno*4, &r, &g, &b);
+			for (i = 0; i < 4; i++)
+				riva_wclut(chip, regno*4+i, r,
+					   green >> 8, b);
 		}
 		break;
 	case 32:
-		if (regno < 16) {
-			((u32 *)info->pseudo_palette)[regno] =
-				((red & 0xff00) << 8) |
-				((green & 0xff00)) | ((blue & 0xff00) >> 8);
-			
-		}
 		riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8);
 		break;
 	default:
@@ -1407,8 +1372,12 @@ static void rivafb_fillrect(struct fb_in
 
 	if (info->var.bits_per_pixel == 8)
 		color = rect->color;
-	else
-		color = ((u32 *)info->pseudo_palette)[rect->color];
+	else {
+		if (par->riva.Architecture != NV_ARCH_03)
+			color = ((u32 *)info->pseudo_palette)[rect->color];
+		else
+			color = par->palette[rect->color];
+	}
 
 	switch (rect->rop) {
 	case ROP_XOR:
@@ -1504,15 +1473,17 @@ static void rivafb_imageblit(struct fb_i
 		bgx = image->bg_color;
 		break;
 	case 16:
-		fgx = ((u32 *)info->pseudo_palette)[image->fg_color];
-		bgx = ((u32 *)info->pseudo_palette)[image->bg_color];
+	case 32:
+		if (par->riva.Architecture != NV_ARCH_03) {
+			fgx = ((u32 *)info->pseudo_palette)[image->fg_color];
+			bgx = ((u32 *)info->pseudo_palette)[image->bg_color];
+		} else {
+			fgx = par->palette[image->fg_color];
+			bgx = par->palette[image->bg_color];
+		}
 		if (info->var.green.length == 6)
 			convert_bgcolor_16(&bgx);	
 		break;
-	case 32:
-		fgx = ((u32 *)info->pseudo_palette)[image->fg_color];
-		bgx = ((u32 *)info->pseudo_palette)[image->bg_color];
-		break;
 	}
 
 	RIVA_FIFO_FREE(par->riva, Bitmap, 7);
@@ -1681,6 +1652,7 @@ static struct fb_ops riva_fb_ops = {
 static int __devinit riva_set_fbinfo(struct fb_info *info)
 {
 	unsigned int cmap_len;
+	struct riva_par *par = (struct riva_par *) info->par;
 
 	NVTRACE_ENTER();
 	info->flags = FBINFO_DEFAULT
@@ -1693,7 +1665,8 @@ static int __devinit riva_set_fbinfo(str
 	info->var = rivafb_default_var;
 	info->fix.visual = (info->var.bits_per_pixel == 8) ?
 				FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
-	info->pseudo_palette = pseudo_palette;
+
+	info->pseudo_palette = par->pseudo_palette;
 
 	cmap_len = riva_get_cmap_len(&info->var);
 	fb_alloc_cmap(&info->cmap, cmap_len, 0);	
@@ -1708,7 +1681,7 @@ static int __devinit riva_set_fbinfo(str
 }
 
 #ifdef CONFIG_PPC_OF
-static int riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
+static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
 {
 	struct riva_par *par = (struct riva_par *) info->par;
 	struct device_node *dp;
@@ -1741,7 +1714,7 @@ static int riva_get_EDID_OF(struct fb_in
 #endif /* CONFIG_PPC_OF */
 
 #ifdef CONFIG_FB_RIVA_I2C
-static int riva_get_EDID_i2c(struct fb_info *info)
+static int __devinit riva_get_EDID_i2c(struct fb_info *info)
 {
 	struct riva_par *par = (struct riva_par *) info->par;
 	int i;
@@ -1760,7 +1733,8 @@ static int riva_get_EDID_i2c(struct fb_i
 }
 #endif /* CONFIG_FB_RIVA_I2C */
 
-static void riva_update_default_var(struct fb_var_screeninfo *var, struct fb_info *info)
+static void __devinit riva_update_default_var(struct fb_var_screeninfo *var,
+					      struct fb_info *info)
 {
 	struct fb_monspecs *specs = &info->monspecs;
 	struct fb_videomode modedb;
@@ -1794,7 +1768,7 @@ static void riva_update_default_var(stru
 }
 
 
-static void riva_get_EDID(struct fb_info *info, struct pci_dev *pdev)
+static void __devinit riva_get_EDID(struct fb_info *info, struct pci_dev *pdev)
 {
 	NVTRACE_ENTER();
 #ifdef CONFIG_PPC_OF
@@ -1808,12 +1782,14 @@ static void riva_get_EDID(struct fb_info
 }
 
 
-static void riva_get_edidinfo(struct fb_info *info)
+static void __devinit riva_get_edidinfo(struct fb_info *info)
 {
 	struct fb_var_screeninfo *var = &rivafb_default_var;
 	struct riva_par *par = (struct riva_par *) info->par;
 
 	fb_edid_to_monspecs(par->EDID, &info->monspecs);
+	fb_videomode_to_modelist(info->monspecs.modedb, info->monspecs.modedb_len,
+				 &info->monspecs.modelist);
 	riva_update_default_var(var, info);
 
 	/* if user specified flatpanel, we respect that */
@@ -1827,7 +1803,7 @@ static void riva_get_edidinfo(struct fb_
  *
  * ------------------------------------------------------------------------- */
 
-static u32 riva_get_arch(struct pci_dev *pd)
+static u32 __devinit riva_get_arch(struct pci_dev *pd)
 {
     	u32 arch = 0;
 
@@ -1983,7 +1959,6 @@ static int __devinit rivafb_probe(struct
 
 	rivafb_fix.smem_len = riva_get_memlen(default_par) * 1024;
 	default_par->dclk_max = riva_get_maxdclk(default_par) * 1000;
-
 	info->screen_base = ioremap(rivafb_fix.smem_start,
 				    rivafb_fix.smem_len);
 	if (!info->screen_base) {
@@ -2016,6 +1991,10 @@ static int __devinit rivafb_probe(struct
 		goto err_out_iounmap_fb;
 	}
 
+	fb_destroy_modedb(info->monspecs.modedb);
+	info->monspecs.modedb_len = 0;
+	info->monspecs.modedb = NULL;
+
 	if (register_framebuffer(info) < 0) {
 		printk(KERN_ERR PFX
 			"error registering riva framebuffer\n");
@@ -2090,7 +2069,6 @@ static void __exit rivafb_remove(struct 
 		iounmap((caddr_t)par->riva.PRAMIN);
 	pci_release_regions(pd);
 	pci_disable_device(pd);
-	fb_destroy_modedb(info->monspecs.modedb);
 	kfree(info->pixmap.addr);
 	kfree(par);
 	kfree(info);
@@ -2153,7 +2131,7 @@ static struct pci_driver rivafb_driver =
  *
  * ------------------------------------------------------------------------- */
 
-int __init rivafb_init(void)
+int __devinit rivafb_init(void)
 {
 	if (pci_register_driver(&rivafb_driver) > 0)
 		return 0;
diff -puN drivers/video/riva/rivafb.h~rivafb-directcolor-mode-and-miscellaneous-fixes drivers/video/riva/rivafb.h
--- 25/drivers/video/riva/rivafb.h~rivafb-directcolor-mode-and-miscellaneous-fixes	2004-08-21 13:47:37.752876224 -0700
+++ 25-akpm/drivers/video/riva/rivafb.h	2004-08-21 13:47:37.774872880 -0700
@@ -44,7 +44,8 @@ struct riva_i2c_chan {
 
 struct riva_par {
 	RIVA_HW_INST riva;	/* interface to riva_hw.c */
-
+	u32 pseudo_palette[16]; /* default palette */
+	u32 palette[16];        /* for Riva128 */
 	caddr_t ctrl_base;	/* virtual control register base addr */
 	unsigned dclk_max;	/* max DCLK */
 
@@ -54,8 +55,6 @@ struct riva_par {
 	struct vgastate state;
 #endif
 	atomic_t ref_count;
-	u32 cursor_data[32 * 32/4];
-	int cursor_reset;
 	unsigned char *EDID;
 	unsigned int Chipset;
 	int forceCRTC;
diff -puN drivers/video/riva/rivafb-i2c.c~rivafb-directcolor-mode-and-miscellaneous-fixes drivers/video/riva/rivafb-i2c.c
--- 25/drivers/video/riva/rivafb-i2c.c~rivafb-directcolor-mode-and-miscellaneous-fixes	2004-08-21 13:47:37.761874856 -0700
+++ 25-akpm/drivers/video/riva/rivafb-i2c.c	2004-08-21 13:47:37.774872880 -0700
@@ -105,8 +105,9 @@ static int riva_setup_i2c_bus(struct riv
 	chan->algo.setscl		= riva_gpio_setscl;
 	chan->algo.getsda		= riva_gpio_getsda;
 	chan->algo.getscl		= riva_gpio_getscl;
-	chan->algo.udelay		= 40;
-	chan->algo.timeout		= 20;
+	chan->algo.udelay		= 5;
+	chan->algo.mdelay               = 5;
+	chan->algo.timeout		= 10;
 	chan->algo.data 		= chan;
 
 	i2c_set_adapdata(&chan->adapter, chan);
diff -puN drivers/video/riva/riva_hw.c~rivafb-directcolor-mode-and-miscellaneous-fixes drivers/video/riva/riva_hw.c
--- 25/drivers/video/riva/riva_hw.c~rivafb-directcolor-mode-and-miscellaneous-fixes	2004-08-21 13:47:37.766874096 -0700
+++ 25-akpm/drivers/video/riva/riva_hw.c	2004-08-21 13:47:37.776872576 -0700
@@ -1299,9 +1299,10 @@ static void CalcStateExt
             break;
     }
 
-    /* Paul Richards: below if block borks things in kernel for some reason */
-    /* if((bpp != 8) && (chip->Architecture != NV_ARCH_03))
-    state->general |= 0x00000030; */
+     /* Paul Richards: below if block borks things in kernel for some reason */
+     /* Tony: Below is needed to set hardware in DirectColor */
+    if((bpp != 8) && (chip->Architecture != NV_ARCH_03))
+	    state->general |= 0x00000030;
 
     state->vpll     = (p << 16) | (n << 8) | m;
     state->repaint0 = (((width/8)*pixelDepth) & 0x700) >> 3;
_
