patch-2.4.0-test2 linux/drivers/video/atyfb.c

Next file: linux/drivers/video/chipsfb.c
Previous file: linux/drivers/video/aty128fb.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test1/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
@@ -1,4 +1,4 @@
-/*  $Id: atyfb.c,v 1.141 2000/03/12 03:53:16 davem Exp $
+/*  $Id: atyfb.c,v 1.142 2000/04/12 01:39:41 davem Exp $
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
  *	Copyright (C) 1997-1998  Geert Uytterhoeven
@@ -475,14 +475,20 @@
 static int currcon = 0;
 
 static struct fb_ops atyfb_ops = {
-    atyfb_open, atyfb_release, atyfb_get_fix, atyfb_get_var, atyfb_set_var,
-    atyfb_get_cmap, atyfb_set_cmap, atyfb_pan_display, atyfb_ioctl,
+	owner:		THIS_MODULE,
+	fb_open:	atyfb_open,
+	fb_release:	atyfb_release,
+	fb_get_fix:	atyfb_get_fix,
+	fb_get_var:	atyfb_get_var,
+	fb_set_var:	atyfb_set_var,
+	fb_get_cmap:	atyfb_get_cmap,
+	fb_set_cmap:	atyfb_set_cmap,
+	fb_pan_display:	atyfb_pan_display,
+	fb_ioctl:	atyfb_ioctl,
 #ifdef __sparc__
-    atyfb_mmap,
-#else
-    NULL,
+	fb_mmap:	atyfb_mmap,
 #endif
-    atyfb_rasterimg
+	fb_rasterimg:	atyfb_rasterimg,
 };
 
 static char atyfb_name[16] = "ATY Mach64";
@@ -536,7 +542,7 @@
     /* mach64CT family / mach64GT (3D RAGE) class */
     { 0x4c42, 0x4c42, "3D RAGE LT PRO (AGP)" },
     { 0x4c44, 0x4c44, "3D RAGE LT PRO" },
-    { 0x4c47, 0x4c47, "3D RAGE LT PRO" },
+    { 0x4c47, 0x4c47, "3D RAGE LT-G" },
     { 0x4c49, 0x4c49, "3D RAGE LT PRO" },
     { 0x4c50, 0x4c50, "3D RAGE LT PRO" },
     { 0x4c54, 0x4c54, "3D RAGE LT" },
@@ -606,6 +612,27 @@
     writeb (val, info->ati_regbase + regindex);
 }
 
+static void aty_st_lcd(int index, u32 val, const struct fb_info_aty *info)
+{
+    unsigned long temp;
+
+    /* write addr byte */
+    temp = aty_ld_le32(LCD_INDEX, info);
+    aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info);
+    /* write the register value */
+    aty_st_le32(LCD_DATA, val, info);
+}
+
+static u32 aty_ld_lcd(int index, const struct fb_info_aty *info)
+{
+    unsigned long temp;
+
+    /* write addr byte */
+    temp = aty_ld_le32(LCD_INDEX, info);
+    aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info);
+    /* read the register value */
+    return aty_ld_le32(LCD_DATA, info);
+}
 
     /*
      *  Generic Mach64 routines
@@ -1031,7 +1058,7 @@
 
 static struct fb_info_aty *fb_list = NULL;
 
-static struct aty_cursor * __init 
+static struct aty_cursor * __init
 aty_init_cursor(struct fb_info_aty *fb)
 {
 	struct aty_cursor *cursor;
@@ -1267,7 +1294,7 @@
 
     gModeReg = 0;
     devSetupRegA = 0;
-    
+
     switch (bpp) {
 	case 8:
 	    gModeReg = 0x83;
@@ -1583,7 +1610,7 @@
 
     /* Calculate the programming word */
     MHz100 = 100000000 / period_in_ps;
-    
+
     program_bits = -1;
     post_divider = 1;
 
@@ -1691,7 +1718,7 @@
     udelay(50000); /* delay for 50 (15) ms */
     aty_st_8(CLOCK_CNTL + info->clk_wr_offset,
 	     ((pll->locationAddr & 0x0F) | CLOCK_STROBE), info);
-   
+
     return;
 }
 
@@ -1711,7 +1738,7 @@
     mach64MinFreq = MIN_FREQ_2595;
     mach64MaxFreq = MAX_FREQ_2595;
     mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
-    
+
     /* Calculate program word */
     if (mhz100 == 0)
 	program_bits = 0xFF;
@@ -1843,7 +1870,7 @@
     mach64MinFreq = MIN_FREQ_2595;
     mach64MaxFreq = MAX_FREQ_2595;
     mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
-    
+
     /* Calculate program word */
     if (mhz100 == 0)
 	program_bits = 0xE0;
@@ -1945,7 +1972,7 @@
     mach64MinFreq = MIN_FREQ_2595;
     mach64MaxFreq = MAX_FREQ_2595;
     mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
-    
+
     save_m = 0;
     save_n = 0;
 
@@ -2359,7 +2386,7 @@
     int accelmode;
     int muxmode;
     u8 tmp;
-    
+
     accelmode = par->accel_flags;  /* hack */
 
     info->current_par = *par;
@@ -2441,7 +2468,7 @@
 		break;
 	}
 	aty_st_le32(MEM_CNTL, i, info);
-					
+
     } else {
 	aty_set_pll_ct(info, &par->pll.ct);
 	i = aty_ld_le32(MEM_CNTL, info) & 0xf00fffff;
@@ -2618,7 +2645,6 @@
 	fb->consolecnt++;
     }
 #endif
-    MOD_INC_USE_COUNT;
     return(0);
 }
 
@@ -2674,7 +2700,6 @@
 	fb->consolecnt--;
     }
 #endif
-    MOD_DEC_USE_COUNT;
     return(0);
 }
 
@@ -2967,7 +2992,7 @@
 #ifdef __sparc__
     struct fbtype fbtyp;
     struct display *disp;
-    
+
     if (con >= 0)
     	disp = &fb_display[con];
     else
@@ -3080,7 +3105,7 @@
 	{
 		unsigned long j, align;
 		int max = -1;
-		
+
 		map_offset = off + size;
 		for (i = 0; fb->mmap_map[i].size; i++) {
 			if (fb->mmap_map[i].voff < off)
@@ -3118,7 +3143,7 @@
 			}
 		}
 	}
-#endif	
+#endif
 
 	/* Each page, see which map applies */
 	for (page = 0; page < size; ) {
@@ -3452,8 +3477,8 @@
     if (default_mclk)
 	mclk = default_mclk;
 
-    printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n", 
-    	   info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20), 
+    printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n",
+    	   info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20),
     	   info->total_vram == 0x80000 ? 'K' : 'M', ramname, xtal, pll, mclk);
 
     if (mclk < 44)
@@ -3517,6 +3542,14 @@
     info->fb_info.blank = &atyfbcon_blank;
     info->fb_info.flags = FBINFO_FLAG_DEFAULT;
 
+#ifdef CONFIG_PPC
+    if (Gx == LI_CHIP_ID && machine_is_compatible("PowerBook1,1")) {
+	/* these bits let the 101 powerbook wake up from sleep -- paulus */
+	aty_st_lcd(LCD_POWER_MANAGEMENT, aty_ld_lcd(LCD_POWER_MANAGEMENT, info)
+		| (USE_F32KHZ | TRISTATE_MEM_EN), info);
+    }
+#endif /* CONFIG_PPC */
+
 #ifdef MODULE
     var = default_var;
 #else /* !MODULE */
@@ -3539,13 +3572,16 @@
 		}
 #endif
 		if (default_vmode == VMODE_CHOOSE) {
-		    if (Gx == LG_CHIP_ID)
+		    if (Gx == LG_CHIP_ID || Gx == LI_CHIP_ID)
 			/* G3 PowerBook with 1024x768 LCD */
 			default_vmode = VMODE_1024_768_60;
-		    else {
-			sense = read_aty_sense(info);
-			default_vmode = mac_map_monitor_sense(sense);
-		    }
+		    else if (machine_is_compatible("iMac"))
+			default_vmode = VMODE_1024_768_75;
+		    else
+			default_vmode = VMODE_640_480_67;
+		    sense = read_aty_sense(info);
+		    printk(KERN_INFO "atyfb: monitor sense=%x, mode %d\n",
+			   sense, mac_map_monitor_sense(sense));
 		}
 		if (default_vmode <= 0 || default_vmode > VMODE_MAX)
 		    default_vmode = VMODE_640_480_60;
@@ -3608,7 +3644,7 @@
 	    info->dispsw.set_font = atyfb_set_font;
 	}
     }
-    
+
     atyfb_set_var(&var, -1, &info->fb_info);
 
     if (register_framebuffer(&info->fb_info) < 0)
@@ -3653,7 +3689,7 @@
 		    break;
 	    if (i < 0)
 		continue;
-	    
+
 	    info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
 	    if (!info) {
 		printk("atyfb_init: can't alloc fb_info_aty\n");
@@ -3714,7 +3750,7 @@
 		io = (rp->flags & IORESOURCE_IO);
 
 		size = rp->end - base + 1;
-		
+
 		pci_read_config_dword(pdev, breg, &pbase);
 
 		if (io)
@@ -4253,7 +4289,7 @@
     if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == GV_CHIP_ID ||
 	Gx == GW_CHIP_ID || Gx == GZ_CHIP_ID || Gx == LG_CHIP_ID ||
 	Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || Gx == GI_CHIP_ID ||
-	Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID)
+	Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || Gx == LI_CHIP_ID)
 	i |= 0x2;	/*DAC_CNTL|0x2 turns off the extra brightness for gt*/
     aty_st_8(DAC_CNTL, i, info);
     aty_st_8(DAC_MASK, 0xff, info);
@@ -4702,6 +4738,124 @@
 #endif
 
 #ifdef CONFIG_PMAC_PBOOK
+
+/* Power management routines. Those are used for PowerBook sleep.
+ *
+ * It appears that Rage LT and Rage LT Pro have different power
+ * management registers. There's is some confusion about which
+ * chipID is a Rage LT or LT pro :(
+ */
+static int
+aty_power_mgmt_LT(int sleep, struct fb_info_aty *info)
+{
+ 	unsigned int pm;
+	int timeout;
+	
+	pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+	pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
+	aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+	pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+	
+	timeout = 200000;
+	if (sleep) {
+		/* Sleep */
+		pm &= ~PWR_MGT_ON;
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+		udelay(10);
+		pm &= ~(PWR_BLON | AUTO_PWR_UP);
+		pm |= SUSPEND_NOW;
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+		udelay(10);
+		pm |= PWR_MGT_ON;
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		do {
+			pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+			udelay(10);
+			if ((--timeout) == 0)
+				break;
+		} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
+	} else {
+		/* Wakeup */
+		pm &= ~PWR_MGT_ON;
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+		udelay(10);
+		pm |=  (PWR_BLON | AUTO_PWR_UP);
+		pm &= ~SUSPEND_NOW;
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+		udelay(10);
+		pm |= PWR_MGT_ON;
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		do {
+			pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+			udelay(10);
+			if ((--timeout) == 0)
+				break;
+		} while ((pm & PWR_MGT_STATUS_MASK) != 0);
+	}
+	mdelay(500);
+
+	return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;
+}
+
+static int
+aty_power_mgmt_LTPro(int sleep, struct fb_info_aty *info)
+{
+ 	unsigned int pm;
+	int timeout;
+	
+	pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+	pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
+	aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+	pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+
+	timeout = 200;
+	if (sleep) {
+		/* Sleep */
+		pm &= ~PWR_MGT_ON;
+		aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+		pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+		udelay(10);
+		pm &= ~(PWR_BLON | AUTO_PWR_UP);
+		pm |= SUSPEND_NOW;
+		aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+		pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+		udelay(10);
+		pm |= PWR_MGT_ON;
+		aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+		do {
+			pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+			udelay(1000);
+			if ((--timeout) == 0)
+				break;
+		} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
+	} else {
+		/* Wakeup */
+		pm &= ~PWR_MGT_ON;
+		aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+		pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+		udelay(10);
+		pm &= ~SUSPEND_NOW;
+		pm |= (PWR_BLON | AUTO_PWR_UP);
+		aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+		pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
+		udelay(10);
+		pm |= PWR_MGT_ON;
+		aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
+		do {
+			pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);			
+			udelay(1000);
+			if ((--timeout) == 0)
+				break;
+		} while ((pm & PWR_MGT_STATUS_MASK) != 0);
+	}
+
+	return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;
+}
+
 /*
  * Save the contents of the frame buffer when we go to sleep,
  * and restore it when we wake up again.
@@ -4710,86 +4864,71 @@
 aty_sleep_notify(struct pmu_sleep_notifier *self, int when)
 {
 	struct fb_info_aty *info;
- 	unsigned int pm;
- 	
+ 	int result;
+
+	result = PBOOK_SLEEP_OK;
+
 	for (info = first_display; info != NULL; info = info->next) {
 		struct fb_fix_screeninfo fix;
 		int nb;
-		
+
 		atyfb_get_fix(&fix, fg_console, (struct fb_info *)info);
 		nb = fb_display[fg_console].var.yres * fix.line_length;
 
 		switch (when) {
+		case PBOOK_SLEEP_REQUEST:
+			info->save_framebuffer = vmalloc(nb);
+			if (info->save_framebuffer == NULL)
+				return PBOOK_SLEEP_REFUSE;
+			break;
+		case PBOOK_SLEEP_REJECT:
+			if (info->save_framebuffer) {
+				vfree(info->save_framebuffer);
+				info->save_framebuffer = 0;
+			}
+			break;
 		case PBOOK_SLEEP_NOW:
+			if (info->blitter_may_be_busy)
+				wait_for_idle(info);
 			/* Stop accel engine (stop bus mastering) */
 			if (info->current_par.accel_flags & FB_ACCELF_TEXT)
 				reset_engine(info);
-#if 1
+
 			/* Backup fb content */	
-			info->save_framebuffer = vmalloc(nb);
 			if (info->save_framebuffer)
-				memcpy(info->save_framebuffer,
+				memcpy_fromio(info->save_framebuffer,
 				       (void *)info->frame_buffer, nb);
-#endif
-			/* Blank display and LCD */				       
-			atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);			
-			
-			/* Set chip to "suspend" mode. Note: There's an HW bug in the
-			   chip which prevents proper resync on wakeup with automatic
-			   power management, we handle suspend manually using the
-			   following (weird) sequence described by ATI. Note2:
-			   We could enable this for all Rage LT Pro chip ids */
-			if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) {
-				pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				pm &= ~PWR_MGT_ON;
-				aty_st_le32(POWER_MANAGEMENT, pm, info);
-				pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				pm &= ~(PWR_BLON | AUTO_PWR_UP);
-				pm |= SUSPEND_NOW;
-				aty_st_le32(POWER_MANAGEMENT, pm, info);
-				pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				pm |= PWR_MGT_ON;
-				aty_st_le32(POWER_MANAGEMENT, pm, info);
-				do {
-					pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
-				mdelay(500);
-			}
+
+			/* Blank display and LCD */
+			atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);
+
+			/* Set chip to "suspend" mode */
+			if (Gx == LG_CHIP_ID)
+				result = aty_power_mgmt_LT(1, info);
+			else
+				result = aty_power_mgmt_LTPro(1, info);
 			break;
 		case PBOOK_WAKE:
 			/* Wakeup chip */
-			if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) {
-				pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				pm &= ~PWR_MGT_ON;
-				aty_st_le32(POWER_MANAGEMENT, pm, info);
-				pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				pm |=  (PWR_BLON | AUTO_PWR_UP);
-				pm &= ~SUSPEND_NOW;
-				aty_st_le32(POWER_MANAGEMENT, pm, info);
-				pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				pm |= PWR_MGT_ON;
-				aty_st_le32(POWER_MANAGEMENT, pm, info);
-				do {
-					pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				} while ((pm & PWR_MGT_STATUS_MASK) != 0);
-				mdelay(500);
-			}
-#if 1
+			if (Gx == LG_CHIP_ID)
+				result = aty_power_mgmt_LT(0, info);
+			else
+				result = aty_power_mgmt_LTPro(0, info);
+
 			/* Restore fb content */			
 			if (info->save_framebuffer) {
-				memcpy((void *)info->frame_buffer,
+				memcpy_toio((void *)info->frame_buffer,
 				       info->save_framebuffer, nb);
 				vfree(info->save_framebuffer);
 				info->save_framebuffer = 0;
 			}
-#endif
-			/* Restore display */			
+			/* Restore display */
 			atyfb_set_par(&info->current_par, info);
 			atyfbcon_blank(0, (struct fb_info *)info);
 			break;
 		}
 	}
-	return PBOOK_SLEEP_OK;
+	return result;
 }
 #endif /* CONFIG_PMAC_PBOOK */
 

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