patch-2.4.21 linux-2.4.21/drivers/video/riva/fbdev.c

Next file: linux-2.4.21/drivers/video/riva/nv4ref.h
Previous file: linux-2.4.21/drivers/video/riva/accel.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/drivers/video/riva/fbdev.c linux-2.4.21/drivers/video/riva/fbdev.c
@@ -1,9 +1,12 @@
 /*
- * linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver
+ * linux/drivers/video/riva/fbdev.c
  *
- * Maintained by Ani Joshi <ajoshi@shell.unixbox.com>
+ * nVidia RIVA 128/TNT/TNT2/GeForce2/3 fb driver
+ *
+ * Maintained by Ani Joshi <ajoshi@kernel.crashing.org>
  *
  * Copyright 1999-2000 Jeff Garzik
+ * Copyright 2000-2003 Ani Joshi
  *
  * Contributors:
  *
@@ -55,7 +58,7 @@
 
 
 /* version number of this driver */
-#define RIVAFB_VERSION "0.9.3"
+#define RIVAFB_VERSION "0.9.4"
 
 
 
@@ -95,7 +98,11 @@
 #define CURSOR_HIDE_DELAY		(20)
 #define CURSOR_SHOW_DELAY		(3)
 
+#ifdef __BIG_ENDIAN
+#define CURSOR_COLOR		0xff7f
+#else
 #define CURSOR_COLOR		0x7fff
+#endif
 #define TRANSPARENT_COLOR	0x0000
 #define MAX_CURS		32
 
@@ -863,6 +870,7 @@
 	struct riva_regs newmode;
 	int bpp, width, hDisplaySize, hDisplay, hStart,
 	    hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock;
+	int hBlankStart, hBlankEnd, vBlankStart, vBlankEnd;
 
 	/* time to calculate */
 
@@ -879,6 +887,8 @@
 		video_mode->hsync_len) / 8 - 1;
 	hTotal = (hDisplaySize + video_mode->right_margin +
 		  video_mode->hsync_len + video_mode->left_margin) / 8 - 1;
+	hBlankStart = hDisplay;
+	hBlankEnd = hTotal;
 	height = video_mode->yres_virtual;
 	vDisplay = video_mode->yres - 1;
 	vStart = video_mode->yres + video_mode->lower_margin - 1;
@@ -886,35 +896,63 @@
 	       video_mode->vsync_len - 1;
 	vTotal = video_mode->yres + video_mode->lower_margin +
 		 video_mode->vsync_len + video_mode->upper_margin + 2;
+	vBlankStart = vDisplay;
+	vBlankEnd = vTotal;
 	dotClock = 1000000000 / video_mode->pixclock;
 
 	memcpy(&newmode, &reg_template, sizeof(struct riva_regs));
 
+	newmode.ext.screen = SetBitField(hBlankEnd,6:6,4:4)
+                  | SetBitField(vBlankStart,10:10,3:3)
+                  | SetBitField(vStart,10:10,2:2)
+                  | SetBitField(vDisplay,10:10,1:1)
+                  | SetBitField(vTotal,10:10,0:0);
+    
+    	newmode.ext.horiz  = SetBitField(hTotal,8:8,0:0)
+                  | SetBitField(hDisplay,8:8,1:1)
+                  | SetBitField(hBlankStart,8:8,2:2)
+                  | SetBitField(hStart,8:8,3:3);
+
+    	newmode.ext.extra  = SetBitField(vTotal,11:11,0:0)
+                    | SetBitField(vDisplay,11:11,2:2)
+                    | SetBitField(vStart,11:11,4:4)
+                    | SetBitField(vBlankStart,11:11,6:6);
+
+	if (rinfo->riva.flatPanel) {
+		vStart = vTotal - 3;
+		vEnd = vTotal - 2;
+		vBlankStart = vStart;
+		hStart = hTotal - 3;
+		hEnd = hTotal - 2;
+		hBlankEnd = hTotal + 4;
+	}
+
 	newmode.crtc[0x0] = Set8Bits (hTotal - 4);
 	newmode.crtc[0x1] = Set8Bits (hDisplay);
-	newmode.crtc[0x2] = Set8Bits (hDisplay);
-	newmode.crtc[0x3] = SetBitField (hTotal, 4: 0, 4:0) | SetBit (7);
+	newmode.crtc[0x2] = Set8Bits (hBlankStart);
+	newmode.crtc[0x3] = SetBitField(hBlankEnd,4:0,4:0)
+                | SetBit(7);
 	newmode.crtc[0x4] = Set8Bits (hStart);
-	newmode.crtc[0x5] = SetBitField (hTotal, 5: 5, 7:7)
-		| SetBitField (hEnd, 4: 0, 4:0);
+	newmode.crtc[0x5] = SetBitField (hBlankEnd, 5: 5, 7:7)
+ 		| SetBitField (hEnd, 4: 0, 4:0);
 	newmode.crtc[0x6] = SetBitField (vTotal, 7: 0, 7:0);
 	newmode.crtc[0x7] = SetBitField (vTotal, 8: 8, 0:0)
 		| SetBitField (vDisplay, 8: 8, 1:1)
 		| SetBitField (vStart, 8: 8, 2:2)
-		| SetBitField (vDisplay, 8: 8, 3:3)
+		| SetBitField (vBlankStart, 8: 8, 3:3)
 		| SetBit (4)
 		| SetBitField (vTotal, 9: 9, 5:5)
 		| SetBitField (vDisplay, 9: 9, 6:6)
 		| SetBitField (vStart, 9: 9, 7:7);
-	newmode.crtc[0x9] = SetBitField (vDisplay, 9: 9, 5:5)
+	newmode.crtc[0x9] = SetBitField (vBlankStart, 9: 9, 5:5)
 		| SetBit (6);
 	newmode.crtc[0x10] = Set8Bits (vStart);
 	newmode.crtc[0x11] = SetBitField (vEnd, 3: 0, 3:0)
 		| SetBit (5);
 	newmode.crtc[0x12] = Set8Bits (vDisplay);
 	newmode.crtc[0x13] = ((width / 8) * ((bpp + 1) / 8)) & 0xFF;
-	newmode.crtc[0x15] = Set8Bits (vDisplay);
-	newmode.crtc[0x16] = Set8Bits (vTotal + 1);
+	newmode.crtc[0x15] = Set8Bits (vBlankStart);
+	newmode.crtc[0x16] = Set8Bits (vBlankEnd);
 
 	newmode.ext.bpp = bpp;
 	newmode.ext.width = width;
@@ -925,11 +963,31 @@
 				  hTotal, height, vDisplay, vStart, vEnd,
 				  vTotal, dotClock);
 
+	newmode.ext.scale = rinfo->riva.PRAMDAC[0x00000848/4] & 0xfff000ff;
+
+	if (rinfo->riva.flatPanel) {
+		newmode.ext.pixel |= (1 << 7);
+		newmode.ext.scale |= (1 << 8);
+	}
+
+	newmode.ext.vpll2 = rinfo->riva.PRAMDAC[0x00000520/4];
+
+#if defined(__powerpc__)
+	/*
+	 * XXX only Mac cards use second DAC for flat panel
+	 */
+	if (rinfo->riva.flatPanel) {
+		newmode.ext.pllsel |= 0x20000800;
+		newmode.ext.vpll2 = newmode.ext.vpll;
+	}
+#endif
 	rinfo->current_state = newmode;
 	riva_load_state(rinfo, &rinfo->current_state);
 
 	rinfo->riva.LockUnlock(&rinfo->riva, 0); /* important for HW cursor */
 	rivafb_download_cursor(rinfo);
+
+	rivafb_blank(0, (struct fb_info *)rinfo);
 }
 
 /**
@@ -1780,6 +1838,10 @@
 		fb_find_mode(&rinfo->disp.var, &rinfo->info, mode_option,
 			     NULL, 0, NULL, 8);
 #endif
+	if (rinfo->use_default_var)
+		/* We will use the modified default var */
+		rinfo->disp.var = rivafb_default_var;
+
 	return 0;
 }
 
@@ -1850,6 +1912,117 @@
 	return 0;
 }
 
+#ifdef CONFIG_ALL_PPC
+static int riva_get_EDID_OF(struct rivafb_info *rinfo)
+{
+	struct device_node *dp;
+	unsigned char *pedid = NULL;
+
+	dp = pci_device_to_OF_node(rinfo->pd);
+	pedid = (unsigned char *)get_property(dp, "EDID,B", 0);
+
+	if (pedid) {
+		rinfo->EDID = pedid;
+		return 1;
+	} else
+		return 0;
+}
+#endif /* CONFIG_ALL_PPC */
+
+static int riva_dfp_parse_EDID(struct rivafb_info *rinfo)
+{
+	unsigned char *block = rinfo->EDID;
+
+	if (!block)
+		return 0;
+
+	/* jump to detailed timing block section */
+	block += 54;
+
+        rinfo->clock = (block[0] + (block[1] << 8));
+        rinfo->panel_xres = (block[2] + ((block[4] & 0xf0) << 4));
+        rinfo->hblank = (block[3] + ((block[4] & 0x0f) << 8));
+        rinfo->panel_yres = (block[5] + ((block[7] & 0xf0) << 4));
+        rinfo->vblank = (block[6] + ((block[7] & 0x0f) << 8));
+        rinfo->hOver_plus = (block[8] + ((block[11] & 0xc0) << 2));
+        rinfo->hSync_width = (block[9] + ((block[11] & 0x30) << 4));
+        rinfo->vOver_plus = ((block[10] >> 4) + ((block[11] & 0x0c) << 2));
+        rinfo->vSync_width = ((block[10] & 0x0f) + ((block[11] & 0x03) << 4));
+        rinfo->interlaced = ((block[17] & 0x80) >> 7);
+        rinfo->synct = ((block[17] & 0x18) >> 3);
+        rinfo->misc = ((block[17] & 0x06) >> 1);
+        rinfo->hAct_high = rinfo->vAct_high = 0;
+        if (rinfo->synct == 3) {
+                if (rinfo->misc & 2)
+                        rinfo->hAct_high = 1;
+                if (rinfo->misc & 1)
+                        rinfo->vAct_high = 1;
+	}
+
+	printk("rivafb: detected DFP panel size from EDID: %dx%d\n",
+		rinfo->panel_xres, rinfo->panel_yres);
+
+	rinfo->got_dfpinfo = 1;
+
+	return 1;
+}
+
+static void riva_update_default_var(struct rivafb_info *rinfo)
+{
+	struct fb_var_screeninfo *var = &rivafb_default_var;
+
+        var->xres = rinfo->panel_xres;
+        var->yres = rinfo->panel_yres;
+        var->xres_virtual = rinfo->panel_xres;
+        var->yres_virtual = rinfo->panel_yres;
+        var->xoffset = var->yoffset = 0;
+        var->bits_per_pixel = 8;
+        var->pixclock = 100000000 / rinfo->clock;
+        var->left_margin = (rinfo->hblank - rinfo->hOver_plus - rinfo->hSync_width);
+        var->right_margin = rinfo->hOver_plus;
+        var->upper_margin = (rinfo->vblank - rinfo->vOver_plus - rinfo->vSync_width);
+        var->lower_margin = rinfo->vOver_plus;
+        var->hsync_len = rinfo->hSync_width;
+        var->vsync_len = rinfo->vSync_width;
+        var->sync = 0;
+
+        if (rinfo->synct == 3) {
+                if (rinfo->hAct_high)
+                        var->sync |= FB_SYNC_HOR_HIGH_ACT;
+                if (rinfo->vAct_high)
+                        var->sync |= FB_SYNC_VERT_HIGH_ACT;
+        }
+ 
+        var->vmode = 0;
+        if (rinfo->interlaced)
+                var->vmode |= FB_VMODE_INTERLACED;
+
+	if (!noaccel)
+		var->accel_flags |= FB_ACCELF_TEXT;
+        
+        rinfo->use_default_var = 1;
+}
+
+
+static void riva_get_EDID(struct rivafb_info *rinfo)
+{
+#ifdef CONFIG_ALL_PPC
+	if (!riva_get_EDID_OF(rinfo))
+		printk("rivafb: could not retrieve EDID from OF\n");
+#else
+	/* XXX use other methods later */
+#endif
+}
+
+
+static void riva_get_dfpinfo(struct rivafb_info *rinfo)
+{
+	if (riva_dfp_parse_EDID(rinfo))
+		riva_update_default_var(rinfo);
+
+	rinfo->riva.flatPanel = rinfo->got_dfpinfo;
+}
+
 
 
 /* ------------------------------------------------------------------------- *
@@ -1880,15 +2053,18 @@
 	rinfo->base0_region_size = pci_resource_len(pd, 0);
 	rinfo->base1_region_size = pci_resource_len(pd, 1);
 
+	{
+		/* enable IO and mem if not already done */
+		unsigned short cmd;
+
+		pci_read_config_word(pd, PCI_COMMAND, &cmd);
+		cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+		pci_write_config_word(pd, PCI_COMMAND, cmd);
+	}
+ 
 	rinfo->ctrl_base_phys = pci_resource_start(rinfo->pd, 0);
 	rinfo->fb_base_phys = pci_resource_start(rinfo->pd, 1);
 
-	if (!request_mem_region(rinfo->ctrl_base_phys,
-				rinfo->base0_region_size, "rivafb")) {
-		printk(KERN_ERR PFX "cannot reserve MMIO region\n");
-		goto err_out_kfree;
-	}
-
 	rinfo->ctrl_base = ioremap(rinfo->ctrl_base_phys,
 				   rinfo->base0_region_size);
 	if (!rinfo->ctrl_base) {
@@ -1896,6 +2072,10 @@
 		goto err_out_free_base1;
 	}
 	
+	riva_get_EDID(rinfo);
+
+	riva_get_dfpinfo(rinfo);
+
 	rinfo->riva.EnableIRQ = 0;
 	rinfo->riva.PRAMDAC = (unsigned *)(rinfo->ctrl_base + 0x00680000);
 	rinfo->riva.PFB = (unsigned *)(rinfo->ctrl_base + 0x00100000);
@@ -1944,6 +2124,19 @@
 		break;
 	}
 
+#if defined(__powerpc__)
+	/*
+	 * XXX Mac cards use the second DAC for the panel
+	 */
+	if (rinfo->riva.flatPanel) {
+		printk("rivafb: using second CRTC\n");
+		rinfo->riva.PCIO = rinfo->riva.PCIO + 0x2000;
+		rinfo->riva.PCRTC = rinfo->riva.PCRTC + 0x800;
+		rinfo->riva.PRAMDAC = rinfo->riva.PRAMDAC + 0x800;
+		rinfo->riva.PDIO = rinfo->riva.PDIO + 0x2000;
+	}
+#endif
+
 	RivaGetConfig(&rinfo->riva);
 
 	rinfo->ram_amount = rinfo->riva.RamAmountKBytes * 1024;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)